Commit 928b3daf authored by madengji's avatar madengji Committed by vipwzw

add util common circuit

parent 9ff24cd5
......@@ -5,7 +5,6 @@ import (
"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/gadgets/hash/mimc"
"github.com/consensys/gurvy"
"strconv"
)
func main() {
......@@ -75,56 +74,3 @@ func NewAuth() *frontend.R1CS {
return r1cs
}
func merkelPathPart(circuit *frontend.CS, mimc mimc.MiMCGadget, noteHash *frontend.Constraint) {
var proofSet, helper, valid []*frontend.Constraint
merkleRoot := circuit.PUBLIC_INPUT("treeRootHash")
proofSet = append(proofSet, noteHash)
//helper[0],valid[0]占位, 方便接口只设置有效值
helper = append(helper, circuit.ALLOCATE("1"))
valid = append(valid, circuit.ALLOCATE("1"))
//depth:10, path num need be 9
for i := 1; i < 10; i++ {
proofSet = append(proofSet, circuit.SECRET_INPUT("path"+strconv.Itoa(i)))
helper = append(helper, circuit.SECRET_INPUT("helper"+strconv.Itoa(i)))
valid = append(valid, circuit.SECRET_INPUT("valid"+strconv.Itoa(i)))
}
VerifyMerkleProof(circuit, mimc, merkleRoot, proofSet, helper, valid)
}
func VerifyMerkleProof(circuit *frontend.CS, h mimc.MiMCGadget, merkleRoot *frontend.Constraint, proofSet, helper, valid []*frontend.Constraint) {
sum := leafSum(circuit, h, proofSet[0])
for i := 1; i < len(proofSet); i++ {
circuit.MUSTBE_BOOLEAN(helper[i])
d1 := circuit.SELECT(helper[i], sum, proofSet[i])
d2 := circuit.SELECT(helper[i], proofSet[i], sum)
rst := nodeSum(circuit, h, d1, d2)
sum = circuit.SELECT(valid[i], rst, sum)
}
// Compare our calculated Merkle root to the desired Merkle root.
circuit.MUSTBE_EQ(sum, merkleRoot)
}
// nodeSum returns the hash created from data inserted to form a leaf.
// Without domain separation.
func nodeSum(circuit *frontend.CS, h mimc.MiMCGadget, a, b *frontend.Constraint) *frontend.Constraint {
res := h.Hash(circuit, a, b)
return res
}
// leafSum returns the hash created from data inserted to form a leaf.
// Without domain separation.
func leafSum(circuit *frontend.CS, h mimc.MiMCGadget, data *frontend.Constraint) *frontend.Constraint {
res := h.Hash(circuit, data)
return res
}
......@@ -3,10 +3,8 @@ package main
import (
"github.com/consensys/gnark/encoding/gob"
"github.com/consensys/gnark/frontend"
twistededwards_gadget "github.com/consensys/gnark/gadgets/algebra/twistededwards"
"github.com/consensys/gnark/gadgets/hash/mimc"
"github.com/consensys/gurvy"
fr_bn256 "github.com/consensys/gurvy/bn256/fr"
)
func main() {
......@@ -95,41 +93,3 @@ func NewTransferInput() *frontend.R1CS {
return r1cs
}
func commitValuePart(circuit *frontend.CS, spendValue *frontend.Constraint) {
//cmt=transfer_value*G + random_value*H
cmtvalueX := circuit.PUBLIC_INPUT("commitValueX")
cmtvalueY := circuit.PUBLIC_INPUT("commitValueY")
// set curve parameters
edgadget, _ := twistededwards_gadget.NewEdCurveGadget(gurvy.BN256)
// set point G in the circuit
pointGSnark := twistededwards_gadget.NewPointGadget(circuit, nil, nil)
//scalar := circuit.ALLOCATE("-1")
circuit.MUSTBE_LESS_OR_EQ(spendValue, 10000000000, 256)
// set point G in the circuit
pointGSnark.ScalarMulFixedBase(circuit, edgadget.BaseX, edgadget.BaseY, spendValue, edgadget)
pointGSnark.X.Tag("xg")
pointGSnark.Y.Tag("yg")
transfer_random := circuit.SECRET_INPUT("spendRandom")
//circuit.MUSTBE_LESS_OR_EQ(random_value,10000000000,256)
//H is not G, H should be a point that no one know the prikey
var baseX_H, baseY_H fr_bn256.Element
baseX_H.SetString("10190477835300927557649934238820360529458681672073866116232821892325659279502")
baseY_H.SetString("7969140283216448215269095418467361784159407896899334866715345504515077887397")
pointHSnark := twistededwards_gadget.NewPointGadget(circuit, nil, nil)
// add points in circuit (the method updates the underlying plain points as well)
pointHSnark.ScalarMulFixedBase(circuit, baseX_H, baseY_H, transfer_random, edgadget)
pointHSnark.X.Tag("xh")
pointHSnark.Y.Tag("yh")
pointSumSnark := twistededwards_gadget.NewPointGadget(circuit, nil, nil)
pointSumSnark.AddGeneric(circuit, &pointGSnark, &pointHSnark, edgadget)
//cmtvalue=transfer_value*G + random_value*H
circuit.MUSTBE_EQ(cmtvalueX, pointSumSnark.X)
circuit.MUSTBE_EQ(cmtvalueY, pointSumSnark.Y)
}
......@@ -48,7 +48,7 @@ func NewTransferOutput() *frontend.R1CS {
//通过merkle tree保证noteHash存在,即便return,auth都是null也是存在的,则可以不经过授权即可消费
//preImage=hash(spendPubkey, returnPubkey,AuthPubkey,spendValue,noteRandom)
noteHash := circuit.SECRET_INPUT("noteHash")
noteHash := circuit.PUBLIC_INPUT("noteHash")
// specify note hash constraint
preImage := mimc.Hash(&circuit, spendPubkey, returnPubkey, authPubkey, spendValue, noteRandom)
circuit.MUSTBE_EQ(noteHash, preImage)
......
......@@ -119,8 +119,9 @@ func TestTransferInputReturnKey(t *testing.T) {
good.Assign(backend.Secret, "authorizePubKey", "13519883267141251871527102103999205179714486518503885909948192364772977661583")
good.Assign(backend.Secret, "spendPriKey", "7969140283216448215269095418467361784159407896899334866715345504515077887397")
//returnkey spend notehash
good.Assign(backend.Secret, "spendFlag", "0")
//not need authorize
good.Assign(backend.Secret, "authorizeFlag", "1")
good.Assign(backend.Secret, "noteRandom", "2824204835")
......@@ -162,3 +163,68 @@ func TestTransferInputReturnKey(t *testing.T) {
}
}
func TestTransferInputNoAuthorize(t *testing.T) {
assert := groth16.NewAssert(t)
r1cs := NewTransferInput()
r1csBN256 := backend_bn256.Cast(r1cs)
{
good := backend.NewAssignment()
good.Assign(backend.Public, "treeRootHash", "12759256930628441934094267209403003086804595141527597228422519500766117029056")
good.Assign(backend.Public, "commitValueX", "14087975867275911077371231345227824611951436822132762463787130558957838320348")
good.Assign(backend.Public, "commitValueY", "15113519960384204624879642069520481336224311978035289236693658603675385299879")
good.Assign(backend.Public, "authorizeSpendHash", "0")
good.Assign(backend.Public, "nullifierHash", "6747518781649068310795677405858353007442326529625450860668944156162052335195")
good.Assign(backend.Secret, "spendAmount", "28242048")
good.Assign(backend.Secret, "spendRandom", "35")
good.Assign(backend.Secret, "spendPubKey", "13735985067536865723202617343666111332145536963656464451727087263423649028705")
good.Assign(backend.Secret, "returnPubKey", "0")
good.Assign(backend.Secret, "authorizePubKey", "0")
good.Assign(backend.Secret, "spendPriKey", "10190477835300927557649934238820360529458681672073866116232821892325659279502")
good.Assign(backend.Secret, "spendFlag", "1")
//not need authorize
good.Assign(backend.Secret, "authorizeFlag", "0")
good.Assign(backend.Secret, "noteRandom", "2824204835")
good.Assign(backend.Secret, "noteHash", "8225571890661960751046682712125507843232543630686326316665478955306869111251")
good.Assign(backend.Secret, "path1", "14187514855908861960780770215596905690354960378277143432325960729637725182251")
good.Assign(backend.Secret, "path2", "6182134257436688306324731906502075484313942414837318361329615447955128796497")
good.Assign(backend.Secret, "path3", "11546648745105756958663742750618707757021496913774959001736226397442926254652")
good.Assign(backend.Secret, "path4", "0")
good.Assign(backend.Secret, "path5", "0")
good.Assign(backend.Secret, "path6", "0")
good.Assign(backend.Secret, "path7", "0")
good.Assign(backend.Secret, "path8", "0")
good.Assign(backend.Secret, "path9", "0")
good.Assign(backend.Secret, "helper1", "1")
good.Assign(backend.Secret, "helper2", "1")
good.Assign(backend.Secret, "helper3", "1")
good.Assign(backend.Secret, "helper4", "0")
good.Assign(backend.Secret, "helper5", "0")
good.Assign(backend.Secret, "helper6", "0")
good.Assign(backend.Secret, "helper7", "0")
good.Assign(backend.Secret, "helper8", "0")
good.Assign(backend.Secret, "helper9", "0")
good.Assign(backend.Secret, "valid1", "1")
good.Assign(backend.Secret, "valid2", "1")
good.Assign(backend.Secret, "valid3", "1")
good.Assign(backend.Secret, "valid4", "0")
good.Assign(backend.Secret, "valid5", "0")
good.Assign(backend.Secret, "valid6", "0")
good.Assign(backend.Secret, "valid7", "0")
good.Assign(backend.Secret, "valid8", "0")
good.Assign(backend.Secret, "valid9", "0")
assert.Solved(&r1csBN256, good, nil)
}
}
package main
import (
"github.com/consensys/gnark/frontend"
twistededwards_gadget "github.com/consensys/gnark/gadgets/algebra/twistededwards"
"github.com/consensys/gnark/gadgets/hash/mimc"
"github.com/consensys/gurvy"
fr_bn256 "github.com/consensys/gurvy/bn256/fr"
"strconv"
)
func merkelPathPart(circuit *frontend.CS, mimc mimc.MiMCGadget, noteHash *frontend.Constraint) {
var proofSet, helper, valid []*frontend.Constraint
merkleRoot := circuit.PUBLIC_INPUT("treeRootHash")
proofSet = append(proofSet, noteHash)
//helper[0],valid[0]占位, 方便接口只设置有效值
helper = append(helper, circuit.ALLOCATE("1"))
valid = append(valid, circuit.ALLOCATE("1"))
//depth:10, path num need be 9
for i := 1; i < 10; i++ {
proofSet = append(proofSet, circuit.SECRET_INPUT("path"+strconv.Itoa(i)))
helper = append(helper, circuit.SECRET_INPUT("helper"+strconv.Itoa(i)))
valid = append(valid, circuit.SECRET_INPUT("valid"+strconv.Itoa(i)))
}
verifyMerkleProof(circuit, mimc, merkleRoot, proofSet, helper, valid)
}
func verifyMerkleProof(circuit *frontend.CS, h mimc.MiMCGadget, merkleRoot *frontend.Constraint, proofSet, helper, valid []*frontend.Constraint) {
sum := leafSum(circuit, h, proofSet[0])
for i := 1; i < len(proofSet); i++ {
circuit.MUSTBE_BOOLEAN(helper[i])
d1 := circuit.SELECT(helper[i], sum, proofSet[i])
d2 := circuit.SELECT(helper[i], proofSet[i], sum)
rst := nodeSum(circuit, h, d1, d2)
sum = circuit.SELECT(valid[i], rst, sum)
}
// Compare our calculated Merkle root to the desired Merkle root.
circuit.MUSTBE_EQ(sum, merkleRoot)
}
// nodeSum returns the hash created from data inserted to form a leaf.
// Without domain separation.
func nodeSum(circuit *frontend.CS, h mimc.MiMCGadget, a, b *frontend.Constraint) *frontend.Constraint {
res := h.Hash(circuit, a, b)
return res
}
// leafSum returns the hash created from data inserted to form a leaf.
// Without domain separation.
func leafSum(circuit *frontend.CS, h mimc.MiMCGadget, data *frontend.Constraint) *frontend.Constraint {
res := h.Hash(circuit, data)
return res
}
func commitValuePart(circuit *frontend.CS, spendValue *frontend.Constraint) {
//cmt=transfer_value*G + random_value*H
cmtvalueX := circuit.PUBLIC_INPUT("commitValueX")
cmtvalueY := circuit.PUBLIC_INPUT("commitValueY")
// set curve parameters
edgadget, _ := twistededwards_gadget.NewEdCurveGadget(gurvy.BN256)
// set point G in the circuit
pointGSnark := twistededwards_gadget.NewPointGadget(circuit, nil, nil)
//scalar := circuit.ALLOCATE("-1")
circuit.MUSTBE_LESS_OR_EQ(spendValue, 10000000000, 256)
// set point G in the circuit
pointGSnark.ScalarMulFixedBase(circuit, edgadget.BaseX, edgadget.BaseY, spendValue, edgadget)
pointGSnark.X.Tag("xg")
pointGSnark.Y.Tag("yg")
transfer_random := circuit.SECRET_INPUT("spendRandom")
//circuit.MUSTBE_LESS_OR_EQ(random_value,10000000000,256)
//H is not G, H should be a point that no one know the prikey
var baseX_H, baseY_H fr_bn256.Element
baseX_H.SetString("10190477835300927557649934238820360529458681672073866116232821892325659279502")
baseY_H.SetString("7969140283216448215269095418467361784159407896899334866715345504515077887397")
pointHSnark := twistededwards_gadget.NewPointGadget(circuit, nil, nil)
// add points in circuit (the method updates the underlying plain points as well)
pointHSnark.ScalarMulFixedBase(circuit, baseX_H, baseY_H, transfer_random, edgadget)
pointHSnark.X.Tag("xh")
pointHSnark.Y.Tag("yh")
pointSumSnark := twistededwards_gadget.NewPointGadget(circuit, nil, nil)
pointSumSnark.AddGeneric(circuit, &pointGSnark, &pointHSnark, edgadget)
//cmtvalue=transfer_value*G + random_value*H
circuit.MUSTBE_EQ(cmtvalueX, pointSumSnark.X)
circuit.MUSTBE_EQ(cmtvalueY, pointSumSnark.Y)
}
/*
Copyright © 2020 ConsenSys
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 cmd
import (
"fmt"
"github.com/spf13/cobra"
"os"
mimcbn256 "github.com/consensys/gnark/crypto/hash/mimc/bn256"
fr_bn256 "github.com/consensys/gurvy/bn256/fr"
)
// verifyCmd represents the verify command
var calcCmd = &cobra.Command{
Use: "calc",
Short: "calc",
Version: Version,
}
var hashCmd = &cobra.Command{
Use: "hash ...",
Short: "read strings to calc hash",
Run: hash,
Version: Version,
}
func init() {
calcCmd.AddCommand(hashCmd)
rootCmd.AddCommand(calcCmd)
}
func hash(cmd *cobra.Command, args []string) {
if len(args) < 1 {
fmt.Println("missing input strings")
os.Exit(-1)
}
var sum []byte
for _, k := range args {
fmt.Println("input:", k)
sum = append(sum, getByte(k)...)
}
hash := mimcbn256.Sum("seed", sum)
fmt.Println("hash=", getFrString(hash))
}
func getByte(v string) []byte {
var fr fr_bn256.Element
fr.SetString(v)
return fr.Bytes()
}
func getFrString(v []byte) string {
var f fr_bn256.Element
f.SetBytes(v)
return f.String()
}
public, nodeHash,16308793397024662832064523892418908145900866571524124093537199035808550255649
public, noteHash,16308793397024662832064523892418908145900866571524124093537199035808550255649
public, amount,28242048
......
public, commitValueX,14087975867275911077371231345227824611951436822132762463787130558957838320348
public, commitValueY,15113519960384204624879642069520481336224311978035289236693658603675385299879
public, nodeHash,16308793397024662832064523892418908145900866571524124093537199035808550255649
public, noteHash,16308793397024662832064523892418908145900866571524124093537199035808550255649
secret, spendAmount,28242048
......
......@@ -70,7 +70,7 @@ func (a *action) depositVerify(proof *mixTy.ZkProofInfo) ([]byte, uint64, error)
return nil, 0, err
}
return transferFr2Bytes(input.NodeHash), val, nil
return transferFr2Bytes(input.NoteHash), val, nil
}
......
......@@ -138,7 +138,7 @@ func (a *action) Transfer(transfer *mixTy.MixTransferAction) (*types.Receipt, er
//push new commit to merkle tree
for _, h := range outputs {
rpt, err := pushTree(a.db, transferFr2Bytes(h.NodeHash))
rpt, err := pushTree(a.db, transferFr2Bytes(h.NoteHash))
if err != nil {
return nil, err
}
......
......@@ -102,7 +102,7 @@ message MixAction {
message DepositPublicInput {
string nodeHash = 1;
string noteHash = 1;
string amount = 2;
}
......@@ -124,7 +124,7 @@ message TransferInputPublicInput {
}
message TransferOutputPublicInput {
string nodeHash = 1;
string noteHash = 1;
string commitValueX = 2;
string commitValueY = 3;
......
......@@ -767,7 +767,7 @@ func (*MixAction) XXX_OneofWrappers() []interface{} {
}
type DepositPublicInput struct {
NodeHash string `protobuf:"bytes,1,opt,name=nodeHash,proto3" json:"nodeHash,omitempty"`
NoteHash string `protobuf:"bytes,1,opt,name=noteHash,proto3" json:"noteHash,omitempty"`
Amount string `protobuf:"bytes,2,opt,name=amount,proto3" json:"amount,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
......@@ -799,9 +799,9 @@ func (m *DepositPublicInput) XXX_DiscardUnknown() {
var xxx_messageInfo_DepositPublicInput proto.InternalMessageInfo
func (m *DepositPublicInput) GetNodeHash() string {
func (m *DepositPublicInput) GetNoteHash() string {
if m != nil {
return m.NodeHash
return m.NoteHash
}
return ""
}
......@@ -948,7 +948,7 @@ func (m *TransferInputPublicInput) GetNullifierHash() string {
}
type TransferOutputPublicInput struct {
NodeHash string `protobuf:"bytes,1,opt,name=nodeHash,proto3" json:"nodeHash,omitempty"`
NoteHash string `protobuf:"bytes,1,opt,name=noteHash,proto3" json:"noteHash,omitempty"`
CommitValueX string `protobuf:"bytes,2,opt,name=commitValueX,proto3" json:"commitValueX,omitempty"`
CommitValueY string `protobuf:"bytes,3,opt,name=commitValueY,proto3" json:"commitValueY,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
......@@ -981,9 +981,9 @@ func (m *TransferOutputPublicInput) XXX_DiscardUnknown() {
var xxx_messageInfo_TransferOutputPublicInput proto.InternalMessageInfo
func (m *TransferOutputPublicInput) GetNodeHash() string {
func (m *TransferOutputPublicInput) GetNoteHash() string {
if m != nil {
return m.NodeHash
return m.NoteHash
}
return ""
}
......@@ -1369,33 +1369,33 @@ var fileDescriptor_5c21d519a9be369a = []byte{
0x89, 0x4e, 0x60, 0xef, 0x4e, 0x96, 0x4c, 0x4e, 0xa1, 0x1e, 0x47, 0xa5, 0x8b, 0xd9, 0xcd, 0xe0,
0x08, 0xcb, 0xe2, 0xa8, 0xec, 0xaa, 0x5e, 0xd8, 0x8e, 0x4b, 0xf7, 0x9b, 0xc5, 0x85, 0x58, 0xf4,
0x35, 0xa8, 0x56, 0x58, 0x3d, 0xbd, 0xc8, 0x03, 0x9f, 0xc5, 0x81, 0x5b, 0x85, 0x65, 0xfb, 0x25,
0x42, 0xc7, 0xb3, 0xdf, 0x05, 0x24, 0xf5, 0x0c, 0xe3, 0x51, 0x46, 0xef, 0xc3, 0x9e, 0xe3, 0x4e,
0x48, 0xd7, 0x5a, 0xce, 0xe4, 0x2e, 0x88, 0xec, 0xc4, 0x18, 0x88, 0x3d, 0x20, 0x2d, 0xe3, 0x0f,
0x05, 0x9e, 0x84, 0x22, 0x93, 0xb9, 0x0c, 0xa8, 0x50, 0x9f, 0x10, 0xec, 0xba, 0x34, 0x91, 0x2f,
0xe5, 0x43, 0xcf, 0xa1, 0xea, 0x04, 0xf3, 0xb9, 0x3d, 0xb5, 0x89, 0xcf, 0x41, 0x22, 0x75, 0xda,
0x89, 0x9a, 0x80, 0x22, 0x05, 0x23, 0x36, 0x49, 0x1c, 0x2a, 0x8e, 0xa8, 0x7b, 0xfe, 0x24, 0x98,
0xe6, 0x53, 0x4c, 0xff, 0x51, 0x40, 0x0f, 0xcb, 0xca, 0x39, 0x3e, 0x96, 0xae, 0x01, 0x95, 0x31,
0x1f, 0xbc, 0xb7, 0xac, 0x86, 0xdf, 0x4b, 0xb6, 0x29, 0xdf, 0x16, 0xe6, 0x07, 0x49, 0x33, 0xe5,
0xdb, 0x21, 0x28, 0xbf, 0x53, 0xd0, 0x7f, 0xca, 0x54, 0xb8, 0xa7, 0x4c, 0xc6, 0x6f, 0xf0, 0x2c,
0x54, 0x37, 0xe0, 0xdb, 0xf9, 0xff, 0x76, 0xf6, 0x1d, 0xc9, 0x32, 0xfe, 0x52, 0xe0, 0x28, 0x79,
0xee, 0x3e, 0xaa, 0xb6, 0x75, 0x38, 0xb0, 0xd2, 0x67, 0xb6, 0xe4, 0xb1, 0xed, 0x66, 0xd5, 0x88,
0x5c, 0x89, 0x49, 0x48, 0x3b, 0x1f, 0x5b, 0x63, 0xa3, 0x06, 0xd0, 0x59, 0xdb, 0x4b, 0xa1, 0x25,
0x71, 0x5f, 0x2a, 0xf5, 0x3d, 0x79, 0x5f, 0xbe, 0x04, 0x4d, 0x1c, 0x3b, 0xa6, 0x4f, 0xc8, 0x1b,
0x62, 0xad, 0x48, 0xfa, 0x5e, 0xad, 0x48, 0xdc, 0x0b, 0x38, 0x88, 0x71, 0x4c, 0xdf, 0xfd, 0xb0,
0xdf, 0x95, 0x24, 0x6e, 0xe8, 0xbb, 0x2b, 0xc2, 0xba, 0xe4, 0xa7, 0x8b, 0x14, 0xd9, 0xec, 0x1f,
0xbf, 0x91, 0x46, 0x44, 0x9c, 0xe4, 0x2a, 0x8e, 0x6c, 0xf4, 0x21, 0x80, 0x27, 0x0e, 0xc8, 0x09,
0x59, 0xf3, 0x7a, 0x54, 0x71, 0xc2, 0x83, 0x3e, 0x00, 0xd5, 0x09, 0x16, 0x82, 0x33, 0xaf, 0x41,
0x15, 0xc7, 0x0e, 0xa4, 0x43, 0x69, 0x46, 0xe6, 0x1e, 0xf1, 0x97, 0x72, 0xb0, 0x42, 0x93, 0xdd,
0x90, 0x9c, 0x9c, 0x45, 0x67, 0x98, 0xfc, 0xf2, 0x10, 0xbd, 0x39, 0xb1, 0xa6, 0x89, 0x5d, 0x1c,
0xd9, 0x8d, 0x1f, 0x01, 0xe2, 0xe7, 0x0e, 0x2a, 0x43, 0xe9, 0xbc, 0x33, 0x1c, 0x8c, 0x7a, 0xa6,
0x96, 0x41, 0x15, 0xd8, 0xbb, 0xea, 0x99, 0xdd, 0x73, 0xdc, 0xbe, 0xd2, 0x14, 0x74, 0x08, 0x55,
0x13, 0xb7, 0xfb, 0xa3, 0x6f, 0x3b, 0xb8, 0xd7, 0x1f, 0x5e, 0x9a, 0x5a, 0x16, 0x21, 0xd8, 0x0f,
0x5d, 0x83, 0x4b, 0x93, 0xf9, 0x72, 0xa8, 0x0a, 0x6a, 0xfb, 0xd2, 0xec, 0x0e, 0x70, 0xef, 0xba,
0xa3, 0xe5, 0x1b, 0xdf, 0x80, 0x1a, 0x3d, 0xbb, 0x58, 0xf6, 0xcb, 0xfe, 0xeb, 0xfe, 0xe0, 0xaa,
0xaf, 0x65, 0x10, 0x40, 0xf1, 0xf4, 0xcd, 0xe8, 0xf8, 0xd5, 0x2b, 0x4d, 0x09, 0xbf, 0xbf, 0xfa,
0x5c, 0xcb, 0x22, 0x15, 0x0a, 0xa7, 0xfd, 0xd6, 0x97, 0x27, 0x5a, 0xae, 0xd1, 0x84, 0x6a, 0xea,
0xdd, 0xc2, 0x92, 0x47, 0x8f, 0x0d, 0x2d, 0x83, 0xf6, 0x01, 0xe2, 0x87, 0x94, 0xa6, 0x34, 0x3e,
0x86, 0x4a, 0xf2, 0xfa, 0x40, 0x25, 0xc8, 0xb5, 0x27, 0x13, 0xb1, 0xd6, 0x39, 0x99, 0x13, 0x4a,
0x34, 0xe5, 0xa6, 0xc8, 0xdf, 0x8e, 0xc7, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0x98, 0xff, 0x1c,
0xdb, 0x48, 0x0a, 0x00, 0x00,
0x42, 0xc7, 0xb3, 0xdf, 0x05, 0x24, 0xf5, 0x0c, 0xe3, 0x51, 0x46, 0xef, 0xc3, 0x9e, 0xe3, 0x52,
0xd2, 0xb5, 0x96, 0x33, 0xb9, 0x0b, 0x22, 0x3b, 0x31, 0x06, 0x62, 0x0f, 0x48, 0xcb, 0xf8, 0x43,
0x81, 0x27, 0xa1, 0xc8, 0x64, 0x2e, 0x03, 0x2a, 0xd4, 0x27, 0x04, 0xbb, 0x2e, 0x4d, 0xe4, 0x4b,
0xf9, 0xd0, 0x73, 0xa8, 0x3a, 0xc1, 0x7c, 0x6e, 0x4f, 0x6d, 0xe2, 0x73, 0x90, 0x48, 0x9d, 0x76,
0xa2, 0x26, 0xa0, 0x48, 0xc1, 0x88, 0x4d, 0x12, 0x87, 0x8a, 0x23, 0xea, 0x9e, 0x3f, 0x09, 0xa6,
0xf9, 0x14, 0xd3, 0x7f, 0x14, 0xd0, 0xc3, 0xb2, 0x72, 0x8e, 0x8f, 0xa5, 0x6b, 0x40, 0x65, 0xcc,
0x07, 0xef, 0x2d, 0xab, 0xe1, 0xf7, 0x92, 0x6d, 0xca, 0xb7, 0x85, 0xf9, 0x41, 0xd2, 0x4c, 0xf9,
0x76, 0x08, 0xca, 0xef, 0x14, 0xf4, 0x9f, 0x32, 0x15, 0xee, 0x29, 0x93, 0xf1, 0x1b, 0x3c, 0x0b,
0xd5, 0x0d, 0xf8, 0x76, 0xfe, 0xbf, 0x9d, 0x7d, 0x47, 0xb2, 0x8c, 0xbf, 0x14, 0x38, 0x4a, 0x9e,
0xbb, 0x8f, 0xaa, 0x6d, 0x1d, 0x0e, 0xac, 0xf4, 0x99, 0x2d, 0x79, 0x6c, 0xbb, 0x59, 0x35, 0x22,
0x57, 0x62, 0x12, 0xd2, 0xce, 0xc7, 0xd6, 0xd8, 0xa8, 0x01, 0x74, 0xd6, 0xf6, 0x52, 0x68, 0x49,
0xdc, 0x97, 0x4a, 0x7d, 0x4f, 0xde, 0x97, 0x2f, 0x41, 0x13, 0xc7, 0x8e, 0xe9, 0x13, 0xf2, 0x86,
0x58, 0x2b, 0x92, 0xbe, 0x57, 0x2b, 0x12, 0xf7, 0x02, 0x0e, 0x62, 0x1c, 0xd3, 0x77, 0x3f, 0xec,
0x77, 0x25, 0x89, 0x1b, 0xfa, 0xee, 0x8a, 0xb0, 0x2e, 0xf9, 0xe9, 0x22, 0x45, 0x36, 0xfb, 0xc7,
0x6f, 0xa4, 0x11, 0x11, 0x27, 0xb9, 0x8a, 0x23, 0x1b, 0x7d, 0x08, 0xe0, 0x89, 0x03, 0x72, 0x42,
0xd6, 0xbc, 0x1e, 0x55, 0x9c, 0xf0, 0xa0, 0x0f, 0x40, 0x75, 0x82, 0x85, 0xe0, 0xcc, 0x6b, 0x50,
0xc5, 0xb1, 0x03, 0xe9, 0x50, 0x9a, 0x91, 0xb9, 0x47, 0xfc, 0xa5, 0x1c, 0xac, 0xd0, 0x64, 0x37,
0x24, 0x27, 0x67, 0xd1, 0x19, 0x26, 0xbf, 0x3c, 0x44, 0x6f, 0x4e, 0xac, 0x69, 0x62, 0x17, 0x47,
0x76, 0xe3, 0x47, 0x80, 0xf8, 0xb9, 0x83, 0xca, 0x50, 0x3a, 0xef, 0x0c, 0x07, 0xa3, 0x9e, 0xa9,
0x65, 0x50, 0x05, 0xf6, 0xae, 0x7a, 0x66, 0xf7, 0x1c, 0xb7, 0xaf, 0x34, 0x05, 0x1d, 0x42, 0xd5,
0xc4, 0xed, 0xfe, 0xe8, 0xdb, 0x0e, 0xee, 0xf5, 0x87, 0x97, 0xa6, 0x96, 0x45, 0x08, 0xf6, 0x43,
0xd7, 0xe0, 0xd2, 0x64, 0xbe, 0x1c, 0xaa, 0x82, 0xda, 0xbe, 0x34, 0xbb, 0x03, 0xdc, 0xbb, 0xee,
0x68, 0xf9, 0xc6, 0x37, 0xa0, 0x46, 0xcf, 0x2e, 0x96, 0xfd, 0xb2, 0xff, 0xba, 0x3f, 0xb8, 0xea,
0x6b, 0x19, 0x04, 0x50, 0x3c, 0x7d, 0x33, 0x3a, 0x7e, 0xf5, 0x4a, 0x53, 0xc2, 0xef, 0xaf, 0x3e,
0xd7, 0xb2, 0x48, 0x85, 0xc2, 0x69, 0xbf, 0xf5, 0xe5, 0x89, 0x96, 0x6b, 0x34, 0xa1, 0x9a, 0x7a,
0xb7, 0xb0, 0xe4, 0xd1, 0x63, 0x43, 0xcb, 0xa0, 0x7d, 0x80, 0xf8, 0x21, 0xa5, 0x29, 0x8d, 0x8f,
0xa1, 0x92, 0xbc, 0x3e, 0x50, 0x09, 0x72, 0xed, 0xc9, 0x44, 0xac, 0x75, 0x4e, 0xe6, 0x84, 0x12,
0x4d, 0xb9, 0x29, 0xf2, 0xb7, 0xe3, 0xf1, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x5f, 0xa6, 0xaa,
0xe3, 0x48, 0x0a, 0x00, 0x00,
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment