├── .gitignore ├── anima.go ├── chains ├── chains.go ├── cosmos │ ├── secp256k1 │ │ └── secp256k1.go │ └── signature │ │ ├── adr36_animo.go │ │ └── verify.go ├── elrond │ ├── personal_sign.go │ └── verify.go ├── evm │ ├── account.go │ ├── cummon.go │ ├── personal_sign.go │ └── recover.go └── starknet │ ├── client │ └── starknet_client.go │ ├── errors │ └── client.go │ ├── signature │ └── verify.go │ └── starknetTypedData │ └── authorization.go ├── cmd ├── generate_issuing_authorization.go └── generate_sharing_authorization.go ├── core ├── issuing_authorization.go └── sign_attributes.go ├── crypto └── hash.go ├── go.mod ├── go.sum ├── models ├── anima.go ├── authorization.go ├── const.go ├── issue.go ├── std_sign_doc.go └── verifier.go ├── protocol ├── endpoints.go ├── protocol.pb.go ├── protocol.proto ├── protocol_grpc.pb.go └── server.go ├── utils ├── array.go └── num.go └── validators └── protocol.go /.gitignore: -------------------------------------------------------------------------------- 1 | *.exe 2 | *.exe~ 3 | *.dll 4 | *.so 5 | *.dylib 6 | 7 | # Test binary, built with `go test -c` 8 | *.test 9 | 10 | # Output of the go coverage tool, specifically when used with LiteIDE 11 | *.out 12 | 13 | # Dependency directories 14 | vendor/ 15 | 16 | # Go workspace file 17 | go.work 18 | 19 | *.env 20 | .vscode 21 | .DS_Store 22 | tmp/ 23 | generate_grpc.sh 24 | 25 | # idea 26 | .idea 27 | -------------------------------------------------------------------------------- /anima.go: -------------------------------------------------------------------------------- 1 | package anima 2 | 3 | import ( 4 | "github.com/anima-protocol/anima-go/core" 5 | "github.com/anima-protocol/anima-go/models" 6 | "github.com/anima-protocol/anima-go/protocol" 7 | "github.com/anima-protocol/anima-go/validators" 8 | ) 9 | 10 | // Issue - Issue new credential to Anima Protocol 11 | func Issue(anima *models.Protocol, issuer *protocol.AnimaIssuer, requestDocument *protocol.IssueDocumentRequest) (*protocol.IssueDocumentResponse, error) { 12 | if err := validators.ValidateProtocol(anima); err != nil { 13 | return nil, err 14 | } 15 | 16 | document, err := core.SignIssuing(anima, issuer, requestDocument, anima.SigningFunc) 17 | if err != nil { 18 | return nil, err 19 | } 20 | 21 | return protocol.Issue(anima, document) 22 | } 23 | 24 | // Verify - Verify Sharing Request from Anima Protocol 25 | func Verify(anima *models.Protocol, request *protocol.VerifyRequest) (*protocol.VerifyResponse, error) { 26 | if err := validators.ValidateProtocol(anima); err != nil { 27 | return &protocol.VerifyResponse{}, err 28 | } 29 | 30 | return protocol.Verify(anima, request) 31 | } 32 | 33 | // RegisterVerifier - Register Verifier on Anima Protocol 34 | func RegisterVerifier(anima *models.Protocol, request *protocol.RegisterVerifierRequest) (*protocol.RegisterVerifierResponse, error) { 35 | if err := validators.ValidateProtocol(anima); err != nil { 36 | return &protocol.RegisterVerifierResponse{}, err 37 | } 38 | 39 | return protocol.RegisterVerifier(anima, request) 40 | } 41 | -------------------------------------------------------------------------------- /chains/chains.go: -------------------------------------------------------------------------------- 1 | package chains 2 | 3 | const ( 4 | ETH = "ETH" 5 | EVM = "EVM" 6 | ELROND = "ELROND" 7 | MULTIVERSX = "MULTIVERSX" 8 | COSMOS = "COSMOS" 9 | STARKNET = "STARKNET" 10 | ) 11 | 12 | var SUPPORTED = map[string]bool{ 13 | ETH: true, 14 | EVM: true, 15 | ELROND: true, 16 | MULTIVERSX: true, 17 | COSMOS: true, 18 | STARKNET: true, 19 | } 20 | -------------------------------------------------------------------------------- /chains/cosmos/secp256k1/secp256k1.go: -------------------------------------------------------------------------------- 1 | package secp256k1 2 | 3 | import ( 4 | "crypto/ecdsa" 5 | "crypto/sha256" 6 | "fmt" 7 | crypto "github.com/anima-protocol/anima-go/crypto" 8 | "github.com/btcsuite/btcd/btcec/v2" 9 | ethCrypto "github.com/ethereum/go-ethereum/crypto" 10 | "golang.org/x/crypto/ripemd160" 11 | "math/big" 12 | ) 13 | 14 | type PubKeySecp256k1 struct { 15 | pubKey []byte 16 | } 17 | 18 | func NewPubKeySecp256k1(pubKey []byte) *PubKeySecp256k1 { 19 | return &PubKeySecp256k1{pubKey: pubKey} 20 | } 21 | 22 | func (pk *PubKeySecp256k1) GetAddress() []byte { 23 | hasherSHA256 := sha256.New() 24 | _, _ = hasherSHA256.Write(pk.pubKey) // does not error 25 | sha := hasherSHA256.Sum(nil) 26 | 27 | hasherRIPEMD160 := ripemd160.New() 28 | _, _ = hasherRIPEMD160.Write(sha) // does not error 29 | 30 | return hasherRIPEMD160.Sum(nil) 31 | } 32 | 33 | func (pk *PubKeySecp256k1) GetEthAddress() []byte { 34 | // Should be uncompressed. . 35 | pubK, err := btcec.ParsePubKey(pk.pubKey) 36 | if err != nil { 37 | return nil 38 | } 39 | 40 | address := ethCrypto.PubkeyToAddress(*pubK.ToECDSA()) 41 | return address.Bytes() 42 | } 43 | 44 | func (pk *PubKeySecp256k1) Verify(msg, signature []byte) (bool, error) { 45 | digest := crypto.HashSHA256Bytes(msg) 46 | return pk.VerifyDigest32(digest[:], signature) 47 | } 48 | 49 | func (pk *PubKeySecp256k1) VerifyDigest32(digest, signature []byte) (bool, error) { 50 | if len(digest) != 32 { 51 | panic(fmt.Sprintf("Invalid length of digest to verify: %d", len(digest))) 52 | } 53 | 54 | if len(signature) != 64 { 55 | panic(fmt.Sprintf("Invalid length of signature: %d", len(signature))) 56 | } 57 | 58 | pubK, err := btcec.ParsePubKey(pk.pubKey) 59 | if err != nil { 60 | return false, fmt.Errorf("Failed to parse public key: %v", err) 61 | } 62 | 63 | r, s := signature[:32], signature[32:] 64 | 65 | return ecdsa.Verify(pubK.ToECDSA(), digest, new(big.Int).SetBytes(r), new(big.Int).SetBytes(s)), nil 66 | } 67 | -------------------------------------------------------------------------------- /chains/cosmos/signature/adr36_animo.go: -------------------------------------------------------------------------------- 1 | package signature 2 | 3 | import ( 4 | "encoding/base64" 5 | "encoding/json" 6 | "fmt" 7 | "github.com/anima-protocol/anima-go/chains/cosmos/secp256k1" 8 | "github.com/anima-protocol/anima-go/crypto" 9 | "github.com/anima-protocol/anima-go/models" 10 | "github.com/btcsuite/btcutil/bech32" 11 | ethCrypto "github.com/ethereum/go-ethereum/crypto" 12 | ) 13 | 14 | func toBech32(address []byte, prefix string) (string, error) { 15 | words, err := bech32.ConvertBits(address, 8, 5, false) 16 | if err != nil { 17 | return "", err 18 | } 19 | 20 | return bech32.Encode(prefix, words) 21 | } 22 | 23 | func MakeADR36AminoSignDoc(signer string, data []byte) models.StdSignDoc { 24 | // data b64 encode 25 | encodedData := base64.StdEncoding.EncodeToString(data) 26 | 27 | return models.StdSignDoc{ 28 | ChainId: "", 29 | AccountNumber: "0", 30 | Sequence: "0", 31 | Fee: models.StdFee{Gas: "0", Amount: []models.Coin{}}, 32 | Msgs: []models.Msg{ 33 | { 34 | Type: "sign/MsgSignData", 35 | Value: models.MsgSignData{Signer: signer, Data: encodedData}, 36 | }, 37 | }, 38 | Memo: "", 39 | } 40 | } 41 | 42 | func VerifyADR36AminoSignDoc( 43 | bech32PrefixAccAddr string, 44 | signDoc models.StdSignDoc, 45 | pubKey []byte, 46 | signature []byte, 47 | algo string, 48 | ) (bool, error) { 49 | cryptoPubkey := secp256k1.NewPubKeySecp256k1(pubKey) 50 | 51 | var addressToConvert []byte 52 | if algo == "ethsecp256k1" { 53 | addressToConvert = cryptoPubkey.GetEthAddress() 54 | } else { 55 | addressToConvert = cryptoPubkey.GetAddress() 56 | } 57 | 58 | expectedSigner, err := toBech32(addressToConvert, bech32PrefixAccAddr) 59 | if err != nil { 60 | return false, err 61 | } 62 | 63 | signer := signDoc.Msgs[0].Value.Signer 64 | 65 | if expectedSigner != signer { 66 | return false, fmt.Errorf("unmatched signer: %s != %s", expectedSigner, signer) 67 | } 68 | 69 | msg, err := json.Marshal(signDoc) 70 | if err != nil { 71 | return false, err 72 | } 73 | 74 | var digest []byte 75 | if algo == "ethsecp256k1" { 76 | digest = ethCrypto.Keccak256(msg) 77 | } else { 78 | digest = crypto.HashSHA256Bytes(msg) 79 | } 80 | 81 | return cryptoPubkey.VerifyDigest32(digest, signature) 82 | } 83 | 84 | func VerifyADR36Amino( 85 | bech32PrefixAccAddr string, 86 | signer string, 87 | data []byte, 88 | pubKey []byte, 89 | signature []byte, 90 | algo string, 91 | ) (bool, error) { 92 | signDoc := MakeADR36AminoSignDoc(signer, data) 93 | 94 | return VerifyADR36AminoSignDoc( 95 | bech32PrefixAccAddr, 96 | signDoc, 97 | pubKey, 98 | signature, 99 | algo, 100 | ) 101 | } 102 | -------------------------------------------------------------------------------- /chains/cosmos/signature/verify.go: -------------------------------------------------------------------------------- 1 | package signature 2 | 3 | import ( 4 | "encoding/base64" 5 | "encoding/json" 6 | "fmt" 7 | "github.com/btcsuite/btcutil/bech32" 8 | "github.com/ethereum/go-ethereum/common/hexutil" 9 | ) 10 | 11 | type Signature struct { 12 | Algorithm string `json:"algorithm"` 13 | StdSignature StdSignature `json:"stdSignature"` 14 | } 15 | 16 | type StdSignature struct { 17 | PubKey PubKey `json:"pub_key"` 18 | Signature string `json:"signature"` 19 | } 20 | 21 | type PubKey struct { 22 | Type string `json:"type"` 23 | Value string `json:"value"` 24 | } 25 | 26 | func VerifyPersonalSignature(publicAddress string, data []byte, userSignature string) error { 27 | //convert userSignature hex string to bytes 28 | sigHex, err := hexutil.Decode(userSignature) 29 | if err != nil { 30 | return err 31 | } 32 | 33 | var sig Signature 34 | err = json.Unmarshal(sigHex, &sig) 35 | if err != nil { 36 | return err 37 | } 38 | 39 | hrp, _, err := bech32.Decode(publicAddress) 40 | if err != nil { 41 | return err 42 | } 43 | 44 | pubKeyBytes, err := base64.StdEncoding.DecodeString(sig.StdSignature.PubKey.Value) 45 | if err != nil { 46 | return err 47 | } 48 | 49 | signatureBytes, err := base64.StdEncoding.DecodeString(sig.StdSignature.Signature) 50 | if err != nil { 51 | return err 52 | } 53 | 54 | success, err := VerifyADR36Amino(hrp, publicAddress, data, pubKeyBytes, signatureBytes, sig.Algorithm) 55 | if err != nil { 56 | return err 57 | } 58 | 59 | if !success { 60 | return fmt.Errorf("signature verification failed") 61 | } 62 | 63 | return nil 64 | } 65 | -------------------------------------------------------------------------------- /chains/elrond/personal_sign.go: -------------------------------------------------------------------------------- 1 | package elrond 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/ethereum/go-ethereum/crypto" 7 | ) 8 | 9 | func GetERDPersonalSignMessage(data []byte) ([]byte, error) { 10 | fmt.Printf("---> ERD = %v\n", string(data)) 11 | rawData := []byte(fmt.Sprintf("\x17Elrond Signed Message:\n%d%s", len(data), data)) 12 | challengeHash := crypto.Keccak256Hash(rawData) 13 | return challengeHash[:], nil 14 | } 15 | -------------------------------------------------------------------------------- /chains/elrond/verify.go: -------------------------------------------------------------------------------- 1 | package elrond 2 | 3 | import ( 4 | "crypto/ed25519" 5 | "encoding/hex" 6 | "fmt" 7 | 8 | "github.com/btcsuite/btcutil/bech32" 9 | ) 10 | 11 | const ElrondHrp = "erd" 12 | 13 | func VerifyPersonalSignature(publicAddress string, data []byte, userSignature string) error { 14 | if len(userSignature) < 3 { 15 | return fmt.Errorf("invalid signature length: %d", len(userSignature)) // TODO: Replace with APIError ? 16 | } 17 | 18 | if userSignature[0:2] == "0x" { 19 | userSignature = userSignature[2:] 20 | } 21 | 22 | message, err := GetERDPersonalSignMessage(data) 23 | if err != nil { 24 | return err 25 | } 26 | 27 | sigBytes, err := hex.DecodeString(userSignature) 28 | if err != nil { 29 | return err 30 | } 31 | 32 | hrp, decodedBech32Addr, err := bech32.Decode(publicAddress) 33 | if err != nil { 34 | return err 35 | } 36 | 37 | if hrp != ElrondHrp { 38 | return fmt.Errorf("invalid hrp from public addres: %s", hrp) 39 | } 40 | 41 | converted, err := bech32.ConvertBits(decodedBech32Addr, 5, 8, false) 42 | if err != nil { 43 | return err 44 | } 45 | valid := ed25519.Verify(converted, message, sigBytes) 46 | if !valid { 47 | return fmt.Errorf("unable to verify signature") 48 | } 49 | 50 | return nil 51 | } 52 | -------------------------------------------------------------------------------- /chains/evm/account.go: -------------------------------------------------------------------------------- 1 | package evm 2 | 3 | import ( 4 | "encoding/hex" 5 | 6 | "github.com/ethereum/go-ethereum/crypto" 7 | ) 8 | 9 | func RecoverAccount(privateKey string) error { 10 | b, err := hex.DecodeString(privateKey) 11 | if err != nil { 12 | return err 13 | } 14 | 15 | if _, err := crypto.ToECDSA(b); err != nil { 16 | return err 17 | } 18 | return nil 19 | } 20 | -------------------------------------------------------------------------------- /chains/evm/cummon.go: -------------------------------------------------------------------------------- 1 | package evm 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "strings" 8 | 9 | ethCrypto "github.com/ethereum/go-ethereum/crypto" 10 | ) 11 | 12 | func VerifySignature(content []byte, sig string, issuerPublicAddress string) error { 13 | credentialContentBytes := new(bytes.Buffer) 14 | 15 | err := json.Compact(credentialContentBytes, content) 16 | if err != nil { 17 | return err 18 | } 19 | 20 | hashedMessage := ethCrypto.Keccak256Hash(credentialContentBytes.Bytes()) 21 | 22 | return verifyEVMSignatureBase(issuerPublicAddress, hashedMessage.Bytes(), sig) 23 | } 24 | 25 | func SignBytes(data []byte, signingFunc func([]byte) (string, error)) (string, error) { 26 | hashedMessage := ethCrypto.Keccak256Hash(data) 27 | 28 | signature, err := signingFunc(hashedMessage.Bytes()) 29 | if err != nil { 30 | return "", err 31 | } 32 | 33 | return signature, nil 34 | } 35 | 36 | func SignInterfaceData(data interface{}, signingFunc func([]byte) (string, error)) (string, error) { 37 | dataByte, err := json.Marshal(&data) 38 | if err != nil { 39 | return "", err 40 | } 41 | 42 | compactedDataByte := new(bytes.Buffer) 43 | err = json.Compact(compactedDataByte, dataByte) 44 | if err != nil { 45 | return "", err 46 | } 47 | 48 | hashedMessage := ethCrypto.Keccak256Hash(compactedDataByte.Bytes()) 49 | 50 | signature, err := signingFunc(hashedMessage.Bytes()) 51 | if err != nil { 52 | return "", err 53 | } 54 | 55 | return signature, nil 56 | } 57 | 58 | func verifyEVMSignatureBase(publicAddress string, data []byte, userSignature string) error { 59 | 60 | recoveredAddr, err := Recover(data, userSignature) 61 | if err != nil { 62 | return err 63 | } 64 | 65 | if !strings.EqualFold(recoveredAddr, publicAddress) { 66 | return fmt.Errorf("public address and signer address does not match") 67 | } 68 | 69 | fmt.Printf("--> All good!\n") 70 | 71 | return nil 72 | } 73 | -------------------------------------------------------------------------------- /chains/evm/personal_sign.go: -------------------------------------------------------------------------------- 1 | package evm 2 | 3 | import ( 4 | "fmt" 5 | 6 | ethCrypto "github.com/ethereum/go-ethereum/crypto" 7 | ) 8 | 9 | func GetEVMPersonalSignMessage(data []byte) ([]byte, error) { 10 | fullMessage := fmt.Sprintf("\x19Ethereum Signed Message:\n%d%s", len(data), data) 11 | hash := ethCrypto.Keccak256Hash([]byte(fullMessage)) 12 | 13 | return hash[:], nil 14 | } 15 | 16 | func VerifyPersonalSignature(publicAddress string, data []byte, userSignature string) error { 17 | message, err := GetEVMPersonalSignMessage(data) 18 | if err != nil { 19 | return err 20 | } 21 | 22 | return verifyEVMSignatureBase(publicAddress, message, userSignature) 23 | } -------------------------------------------------------------------------------- /chains/evm/recover.go: -------------------------------------------------------------------------------- 1 | package evm 2 | 3 | import ( 4 | "encoding/hex" 5 | "fmt" 6 | "strings" 7 | 8 | "github.com/ethereum/go-ethereum/crypto" 9 | ) 10 | 11 | func Recover(data []byte, userSignature string) (string, error) { 12 | 13 | if len(userSignature) < 3 { 14 | return "", fmt.Errorf("invalid signature length: %d", len(userSignature)) // TODO: Replace with APIError ? 15 | } 16 | 17 | if userSignature[0:2] == "0x" { 18 | userSignature = userSignature[2:] 19 | } 20 | 21 | signature, err := hex.DecodeString(userSignature) 22 | if err != nil { 23 | return "", err 24 | } 25 | 26 | if len(signature) != 65 { 27 | return "", fmt.Errorf("invalid signature length: %d", len(signature)) 28 | } 29 | 30 | if signature[64] == 27 || signature[64] == 28 { 31 | signature[64] -= 27 32 | } 33 | 34 | if signature[64] != 0 && signature[64] != 1 { 35 | return "", fmt.Errorf("invalid recovery id: %d", signature[64]) 36 | } 37 | 38 | pubKeyRaw, err := crypto.Ecrecover(data, signature) 39 | if err != nil { 40 | return "", fmt.Errorf("invalid signature: %s", err.Error()) 41 | } 42 | 43 | pubKey, err := crypto.UnmarshalPubkey(pubKeyRaw) 44 | if err != nil { 45 | return "", err 46 | } 47 | 48 | recoveredAddr := crypto.PubkeyToAddress(*pubKey) 49 | 50 | fmt.Printf("address = %v\n", recoveredAddr.String()) 51 | return strings.ToLower(recoveredAddr.String()), nil 52 | } 53 | -------------------------------------------------------------------------------- /chains/starknet/client/starknet_client.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "context" 5 | "github.com/NethermindEth/juno/core/felt" 6 | "github.com/NethermindEth/starknet.go/rpc" 7 | "github.com/NethermindEth/starknet.go/utils" 8 | "math/big" 9 | "strings" 10 | 11 | "github.com/anima-protocol/anima-go/chains/starknet/errors" 12 | ) 13 | 14 | type StarknetClient struct { 15 | provider *rpc.Provider 16 | } 17 | 18 | func NewStarknetClient(providerUrl string) *StarknetClient { 19 | provider, err := rpc.NewProvider(providerUrl) 20 | if err != nil { 21 | panic(err) 22 | } 23 | return &StarknetClient{ 24 | provider: provider, 25 | } 26 | } 27 | 28 | func (c *StarknetClient) IsValidSignature(context context.Context, address string, messageHash *big.Int, fullSignature []string) (bool, error) { 29 | contractAddress, err := utils.HexToFelt(address) 30 | if err != nil { 31 | return false, err 32 | } 33 | 34 | var signatureCallData []*felt.Felt 35 | 36 | for _, sig := range fullSignature { 37 | signatureCallData = append(signatureCallData, utils.BigIntToFelt(utils.StrToBig(sig))) 38 | } 39 | 40 | tx := rpc.FunctionCall{ 41 | ContractAddress: contractAddress, 42 | EntryPointSelector: utils.GetSelectorFromNameFelt("isValidSignature"), 43 | Calldata: append([]*felt.Felt{ 44 | utils.BigIntToFelt(messageHash), 45 | utils.Uint64ToFelt(uint64(len(fullSignature))), 46 | }, signatureCallData...), 47 | } 48 | 49 | callResp, err := c.provider.Call(context, tx, rpc.BlockID{Tag: "latest"}) 50 | 51 | if err != nil { 52 | if strings.Contains(err.Error(), "StarknetErrorCode.UNINITIALIZED_CONTRACT") { 53 | return false, errors.Error_Not_Deployed 54 | } 55 | return false, nil 56 | } else if callResp[0].String() == "0x1" { 57 | return true, nil 58 | } 59 | return false, nil 60 | } 61 | -------------------------------------------------------------------------------- /chains/starknet/errors/client.go: -------------------------------------------------------------------------------- 1 | package errors 2 | 3 | import "errors" 4 | 5 | var Error_Not_Deployed = errors.New("account not deployed") 6 | -------------------------------------------------------------------------------- /chains/starknet/signature/verify.go: -------------------------------------------------------------------------------- 1 | package signature 2 | 3 | import ( 4 | "context" 5 | "encoding/hex" 6 | "encoding/json" 7 | "fmt" 8 | "github.com/anima-protocol/anima-go/chains/starknet/client" 9 | "github.com/anima-protocol/anima-go/chains/starknet/starknetTypedData" 10 | "github.com/ethereum/go-ethereum/common/hexutil" 11 | "strings" 12 | 13 | "github.com/NethermindEth/starknet.go/utils" 14 | ) 15 | 16 | type StarknetSignature struct { 17 | ChainId string `json:"chainId"` 18 | Signature Signature `json:"signature"` 19 | FullSignature []string `json:"fullSignature"` 20 | } 21 | 22 | type Signature struct { 23 | R string `json:"r"` 24 | S string `json:"s"` 25 | } 26 | 27 | func VerifyPersonalSignature(publicAddress string, data []byte, userSignature string, rpcProviderUrl string) error { 28 | ctx := context.Background() 29 | // convert userSignature hex string to bytes 30 | sigHex, err := hexutil.Decode(userSignature) 31 | if err != nil { 32 | return err 33 | } 34 | 35 | var sig StarknetSignature 36 | err = json.Unmarshal(sigHex, &sig) 37 | if err != nil { 38 | return err 39 | } 40 | 41 | typedDataMessage, err := starknetTypedData.CreateStarknetAuthorizationTypedDataMessage(data) 42 | if err != nil { 43 | return err 44 | } 45 | 46 | typedData, err := starknetTypedData.CreateStarknetAuthorizationTypedDataDefinition(sig.ChainId, typedDataMessage) 47 | if err != nil { 48 | return err 49 | } 50 | 51 | messageHash, err := typedData.GetMessageHash(publicAddress) 52 | if err != nil { 53 | return err 54 | } 55 | 56 | if strings.HasPrefix(sig.ChainId, "0x") { 57 | chainIdWithoutPrefix := sig.ChainId[2:] 58 | bs, err := hex.DecodeString(chainIdWithoutPrefix) 59 | if err != nil { 60 | return err 61 | } 62 | sig.ChainId = string(bs) 63 | } 64 | 65 | var finalSignature []string 66 | 67 | if sig.FullSignature == nil || len(sig.FullSignature) == 0 { 68 | finalSignature = []string{sig.Signature.R, sig.Signature.S} 69 | } else { 70 | finalSignature = sig.FullSignature 71 | } 72 | 73 | starknetClient := client.NewStarknetClient(rpcProviderUrl) 74 | 75 | valid, err := starknetClient.IsValidSignature(ctx, publicAddress, utils.FeltToBigInt(messageHash), finalSignature) 76 | if err != nil { 77 | return err 78 | } 79 | 80 | if !valid { 81 | return fmt.Errorf("invalid signature") 82 | } 83 | 84 | return nil 85 | } 86 | -------------------------------------------------------------------------------- /chains/starknet/starknetTypedData/authorization.go: -------------------------------------------------------------------------------- 1 | package starknetTypedData 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/NethermindEth/starknet.go/typedData" 6 | "github.com/anima-protocol/anima-go/crypto" 7 | ) 8 | 9 | type StarknetAuthorizationMessage struct { 10 | Hash0 string `json:"hash0"` 11 | Hash1 string `json:"hash1"` 12 | Hash2 string `json:"hash2"` 13 | } 14 | 15 | func CreateStarknetAuthorizationTypedDataDefinition( 16 | chainId string, 17 | message []byte, 18 | ) (td *typedData.TypedData, err error) { 19 | var animaTypes []typedData.TypeDefinition 20 | 21 | domDefs := []typedData.TypeParameter{ 22 | {Name: "name", Type: "felt"}, 23 | {Name: "chainId", Type: "felt"}, 24 | {Name: "version", Type: "felt"}, 25 | } 26 | 27 | animaTypes = append( 28 | animaTypes, typedData.TypeDefinition{ 29 | Name: "StarkNetDomain", 30 | Parameters: domDefs, 31 | }, 32 | ) 33 | 34 | msgDefs := []typedData.TypeParameter{ 35 | {Name: "hash0", Type: "felt"}, 36 | {Name: "hash1", Type: "felt"}, 37 | {Name: "hash2", Type: "felt"}, 38 | } 39 | animaTypes = append( 40 | animaTypes, typedData.TypeDefinition{ 41 | Name: "Message", 42 | Parameters: msgDefs, 43 | }, 44 | ) 45 | 46 | domain := typedData.Domain{ 47 | Name: "Anima", 48 | Version: "1.0.0", 49 | ChainId: chainId, 50 | } 51 | 52 | return typedData.NewTypedData(animaTypes, "Message", domain, message) 53 | } 54 | 55 | func CreateStarknetAuthorizationTypedDataMessage(data []byte) ([]byte, error) { 56 | hash := crypto.HashSHA256(data) 57 | 58 | m := StarknetAuthorizationMessage{ 59 | Hash0: hash[:31], 60 | Hash1: hash[31:62], 61 | Hash2: hash[62:], 62 | } 63 | 64 | return json.Marshal(m) 65 | } 66 | -------------------------------------------------------------------------------- /cmd/generate_issuing_authorization.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/base64" 5 | "encoding/hex" 6 | "encoding/json" 7 | "flag" 8 | "fmt" 9 | "log" 10 | "math/rand" 11 | "os" 12 | "time" 13 | 14 | "github.com/anima-protocol/anima-go/chains/evm" 15 | crypto2 "github.com/anima-protocol/anima-go/crypto" 16 | "github.com/anima-protocol/anima-go/models" 17 | "github.com/anima-protocol/anima-go/utils" 18 | "github.com/ethereum/go-ethereum/common/math" 19 | "github.com/ethereum/go-ethereum/crypto" 20 | "github.com/ethereum/go-ethereum/signer/core/apitypes" 21 | "github.com/joho/godotenv" 22 | ) 23 | 24 | type IssuingAuthorization struct { 25 | Content string `json:"content"` 26 | Signature string `json:"signature"` 27 | } 28 | 29 | const ( 30 | PASSORT string = "anima:schema:document/passport@1.0.0" 31 | ID = "anima:schema:document/national_id@1.0.0" 32 | DRIVER_LICENSE = "anima:schema:document/driver_license@1.0.0" 33 | RESIDENT_PERMIT = "anima:schema:document/resident_permit@1.0.0" 34 | LIVENESS = "anima:schema:document/liveness@1.0.0" 35 | FACE = "anima:schema:pop@1.0.0" 36 | ) 37 | 38 | var documentSpecsName = []string{ 39 | PASSORT, 40 | ID, 41 | DRIVER_LICENSE, 42 | RESIDENT_PERMIT, 43 | LIVENESS, 44 | FACE, 45 | } 46 | 47 | func loadEnv() { 48 | err := godotenv.Load() 49 | if err != nil { 50 | log.Fatal("Cannot load '.env' file, terminating.") 51 | } 52 | } 53 | 54 | func getEnv(evar string) string { 55 | val := os.Getenv(evar) 56 | if val == "" { 57 | log.Fatalf("[MISSING EVAR] %v\n", evar) 58 | os.Exit(1) 59 | } 60 | return val 61 | } 62 | 63 | func generateFields(specs string) map[string]interface{} { 64 | switch specs { 65 | case PASSORT: 66 | return map[string]interface{}{ 67 | "original_passport_page": "41a4547b3caa10e7c81789a02ccf8f28f861ad5e58d29ea6ac4b004e179c05c2", 68 | } 69 | case ID, DRIVER_LICENSE, RESIDENT_PERMIT: 70 | return map[string]interface{}{ 71 | "original_document_front": "fb2e6923ee3290f90adb76851a6b515b1ac50c976285eb3b68bb2b091457cd7f", 72 | "original_document_back": "ac521e88646e7cdf7685f5d4e5447bd982eade98429e46111064b0462d84cb95", 73 | } 74 | case LIVENESS: 75 | return map[string]interface{}{ 76 | "facegraph": "17f71ed4d556a3ba04707ed8f727159739e367b45589e48fcd8ea2756a1ed4b1", 77 | "audit_trail": crypto2.HashSHA256Str("audit_trail"), 78 | "face": crypto2.HashSHA256Str("face"), 79 | } 80 | case FACE: 81 | return map[string]interface{}{ 82 | "facegraph": "17f71ed4d556a3ba04707ed8f727159739e367b45589e48fcd8ea2756a1ed4b1", 83 | } 84 | } 85 | 86 | return map[string]interface{}{} 87 | } 88 | 89 | func generateAttributes(specs string) map[string]bool { 90 | switch specs { 91 | case PASSORT: 92 | return map[string]bool{ 93 | "firstname": true, 94 | "lastname": true, 95 | "birth_date": true, 96 | "nationality": true, 97 | "document_country": true, 98 | "document_number": true, 99 | "document_expiration": true, 100 | "passport_page": true, 101 | "original_passport_page": true, 102 | } 103 | case ID, RESIDENT_PERMIT: 104 | return map[string]bool{ 105 | "firstname": true, 106 | "lastname": true, 107 | "birth_date": true, 108 | "nationality": true, 109 | "document_country": true, 110 | "document_number": true, 111 | "document_expiration": true, 112 | "document_front": true, 113 | "original_document_front": true, 114 | "document_back": true, 115 | "original_document_back": true, 116 | } 117 | case DRIVER_LICENSE: 118 | return map[string]bool{ 119 | "firstname": true, 120 | "lastname": true, 121 | "birth_date": true, 122 | "document_country": true, 123 | "document_number": true, 124 | "document_expiration": true, 125 | "document_front": true, 126 | "original_document_front": true, 127 | "document_back": true, 128 | "original_document_back": true, 129 | } 130 | case LIVENESS: 131 | return map[string]bool{ 132 | "facegraph": true, 133 | "audit_trail": true, 134 | "face": true, 135 | } 136 | case FACE: 137 | return map[string]bool{ 138 | "facegraph": true, 139 | } 140 | } 141 | return map[string]bool{} 142 | } 143 | 144 | func generateFieldsTypes(specs string) []apitypes.Type { 145 | switch specs { 146 | case PASSORT: 147 | return []apitypes.Type{ 148 | { 149 | Name: "original_passport_page", 150 | Type: "string", 151 | }, 152 | } 153 | case ID, RESIDENT_PERMIT, DRIVER_LICENSE: 154 | return []apitypes.Type{ 155 | { 156 | Name: "original_document_front", 157 | Type: "string", 158 | }, 159 | { 160 | Name: "original_document_back", 161 | Type: "string", 162 | }, 163 | } 164 | case LIVENESS: 165 | return []apitypes.Type{ 166 | { 167 | Name: "facegraph", 168 | Type: "string", 169 | }, 170 | { 171 | Name: "audit_trail", 172 | Type: "string", 173 | }, 174 | { 175 | Name: "face", 176 | Type: "string", 177 | }, 178 | } 179 | case FACE: 180 | return []apitypes.Type{ 181 | { 182 | Name: "facegraph", 183 | Type: "string", 184 | }, 185 | } 186 | } 187 | return []apitypes.Type{} 188 | } 189 | 190 | func generateAttributesTypes(specs string) []apitypes.Type { 191 | switch specs { 192 | case PASSORT: 193 | return []apitypes.Type{ 194 | { 195 | Name: "firstname", 196 | Type: "bool", 197 | }, 198 | { 199 | Name: "lastname", 200 | Type: "bool", 201 | }, 202 | { 203 | Name: "birth_date", 204 | Type: "bool", 205 | }, 206 | { 207 | Name: "nationality", 208 | Type: "bool", 209 | }, 210 | { 211 | Name: "document_country", 212 | Type: "bool", 213 | }, 214 | { 215 | Name: "document_number", 216 | Type: "bool", 217 | }, 218 | { 219 | Name: "document_expiration", 220 | Type: "bool", 221 | }, 222 | { 223 | Name: "passport_page", 224 | Type: "bool", 225 | }, 226 | { 227 | Name: "original_passport_page", 228 | Type: "bool", 229 | }, 230 | } 231 | case ID, RESIDENT_PERMIT: 232 | return []apitypes.Type{ 233 | { 234 | Name: "firstname", 235 | Type: "bool", 236 | }, 237 | { 238 | Name: "lastname", 239 | Type: "bool", 240 | }, 241 | { 242 | Name: "birth_date", 243 | Type: "bool", 244 | }, 245 | { 246 | Name: "nationality", 247 | Type: "bool", 248 | }, 249 | { 250 | Name: "document_country", 251 | Type: "bool", 252 | }, 253 | { 254 | Name: "document_number", 255 | Type: "bool", 256 | }, 257 | { 258 | Name: "document_expiration", 259 | Type: "bool", 260 | }, 261 | { 262 | Name: "document_front", 263 | Type: "bool", 264 | }, 265 | { 266 | Name: "original_document_front", 267 | Type: "bool", 268 | }, 269 | { 270 | Name: "document_back", 271 | Type: "bool", 272 | }, 273 | { 274 | Name: "original_document_back", 275 | Type: "bool", 276 | }, 277 | } 278 | case DRIVER_LICENSE: 279 | return []apitypes.Type{ 280 | { 281 | Name: "firstname", 282 | Type: "bool", 283 | }, 284 | { 285 | Name: "lastname", 286 | Type: "bool", 287 | }, 288 | { 289 | Name: "birth_date", 290 | Type: "bool", 291 | }, 292 | { 293 | Name: "document_country", 294 | Type: "bool", 295 | }, 296 | { 297 | Name: "document_number", 298 | Type: "bool", 299 | }, 300 | { 301 | Name: "document_expiration", 302 | Type: "bool", 303 | }, 304 | { 305 | Name: "document_front", 306 | Type: "bool", 307 | }, 308 | { 309 | Name: "original_document_front", 310 | Type: "bool", 311 | }, 312 | { 313 | Name: "document_back", 314 | Type: "bool", 315 | }, 316 | { 317 | Name: "original_document_back", 318 | Type: "bool", 319 | }, 320 | } 321 | case LIVENESS: 322 | return []apitypes.Type{ 323 | { 324 | Name: "facegraph", 325 | Type: "bool", 326 | }, 327 | { 328 | Name: "audit_trail", 329 | Type: "bool", 330 | }, 331 | { 332 | Name: "face", 333 | Type: "bool", 334 | }, 335 | } 336 | case FACE: 337 | return []apitypes.Type{ 338 | { 339 | Name: "facegraph", 340 | Type: "bool", 341 | }, 342 | } 343 | } 344 | return []apitypes.Type{} 345 | } 346 | 347 | func generateTypes(specs string) apitypes.Types { 348 | baseType := apitypes.Types{ 349 | "Main": []apitypes.Type{ 350 | { 351 | Name: "issuer", 352 | Type: "Issuer", 353 | }, 354 | { 355 | Name: "owner", 356 | Type: "Owner", 357 | }, 358 | { 359 | Name: "specs", 360 | Type: "string", 361 | }, 362 | { 363 | Name: "requested_at", 364 | Type: "uint64", 365 | }, 366 | { 367 | Name: "fields", 368 | Type: "Fields", 369 | }, 370 | { 371 | Name: "attributes", 372 | Type: "Attributes", 373 | }, 374 | }, 375 | "Fields": generateFieldsTypes(specs), 376 | "Attributes": generateAttributesTypes(specs), 377 | "Owner": []apitypes.Type{ 378 | { 379 | Name: "id", 380 | Type: "string", 381 | }, 382 | { 383 | Name: "public_address", 384 | Type: "address", 385 | }, 386 | { 387 | Name: "public_key_encryption", 388 | Type: "string", 389 | }, 390 | { 391 | Name: "chain", 392 | Type: "string", 393 | }, 394 | }, 395 | "Issuer": []apitypes.Type{ 396 | { 397 | Name: "id", 398 | Type: "string", 399 | }, 400 | { 401 | Name: "public_address", 402 | Type: "address", 403 | }, 404 | { 405 | Name: "chain", 406 | Type: "string", 407 | }, 408 | }, 409 | "EIP712Domain": []apitypes.Type{ 410 | { 411 | Name: "name", 412 | Type: "string", 413 | }, 414 | { 415 | Name: "chainId", 416 | Type: "uint256", 417 | }, 418 | { 419 | Name: "version", 420 | Type: "string", 421 | }, 422 | }, 423 | } 424 | return baseType 425 | } 426 | 427 | func main() { 428 | loadEnv() 429 | PRIVATE_OWNER_SIGNING_KEY := getEnv("PRIVATE_OWNER_SIGNING_KEY") 430 | PUBLIC_OWNER_ADDRESS := getEnv("PUBLIC_OWNER_ADDRESS") 431 | PUBLIC_OWNER_ENCRYPTION_KEY := getEnv("PUBLIC_OWNER_ENCRYPTION_KEY") 432 | 433 | specsPtr := flag.String("specs", documentSpecsName[rand.Intn(len(documentSpecsName))], "specs type to generate") 434 | validPtr := flag.Bool("valid", true, "is signature valid or not") 435 | 436 | flag.Parse() 437 | if !utils.InArray(*specsPtr, documentSpecsName) { 438 | log.Fatal("Invalid specs value") 439 | os.Exit(1) 440 | } 441 | 442 | authorization := &evm.IssuingAuthorizationEIP712{ 443 | Domain: apitypes.TypedDataDomain{ 444 | Name: models.PROTOCOL_NAME, 445 | Version: models.PROTOCOL_VERSION, 446 | ChainId: math.NewHexOrDecimal256(models.CHAIN_ETH_ID), 447 | }, 448 | Message: models.IssuingAuthorization{ 449 | Specs: *specsPtr, 450 | RequestedAt: uint64(time.Now().Unix()), 451 | Fields: generateFields(*specsPtr), 452 | Attributes: generateAttributes(*specsPtr), 453 | Owner: models.AnimaOwner{ 454 | ID: fmt.Sprintf("anima:owner:%s", PUBLIC_OWNER_ADDRESS), 455 | PublicAddress: PUBLIC_OWNER_ADDRESS, 456 | PublicKeyEncryption: PUBLIC_OWNER_ENCRYPTION_KEY, 457 | Chain: "EVM", 458 | }, 459 | Issuer: models.AnimaIssuer{ 460 | ID: "anima:issuer:synaps@1.0.0", 461 | PublicAddress: "0x6bf88580aF74117322bB4bA54Ac497A66B77B4B6", 462 | Chain: "ETH", 463 | }, 464 | }, 465 | Types: generateTypes(*specsPtr), 466 | } 467 | 468 | challenge, err := json.Marshal(authorization) 469 | if err != nil { 470 | log.Fatal("Error while transforming authorization in json") 471 | os.Exit(1) 472 | } 473 | 474 | challengeHash, err := evm.GetEIP712Message(challenge) 475 | 476 | fmt.Printf("%v\n", err) 477 | 478 | privateKey, _ := crypto.HexToECDSA(PRIVATE_OWNER_SIGNING_KEY) 479 | signature, err := crypto.Sign(challengeHash, privateKey) 480 | if err != nil { 481 | fmt.Printf("Error while signing: %v\n", err) 482 | os.Exit(1) 483 | } 484 | if *validPtr == false { 485 | signature[2] = 23 486 | signature[3] = 23 487 | signature[4] = 23 488 | } 489 | hexSignature := "0x" + hex.EncodeToString(signature) 490 | 491 | base64Challenge := base64.StdEncoding.EncodeToString(challenge) 492 | 493 | result := IssuingAuthorization{ 494 | Content: base64Challenge, 495 | Signature: hexSignature, 496 | } 497 | 498 | jsonResult, _ := json.Marshal(result) 499 | 500 | fmt.Print(string(jsonResult)) 501 | } 502 | -------------------------------------------------------------------------------- /cmd/generate_sharing_authorization.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/base64" 5 | "encoding/hex" 6 | "encoding/json" 7 | "fmt" 8 | "log" 9 | "os" 10 | "time" 11 | 12 | "github.com/anima-protocol/anima-go/chains/evm" 13 | animaCrypto "github.com/anima-protocol/anima-go/crypto" 14 | "github.com/anima-protocol/anima-go/models" 15 | "github.com/ethereum/go-ethereum/common/math" 16 | "github.com/ethereum/go-ethereum/crypto" 17 | "github.com/ethereum/go-ethereum/signer/core/apitypes" 18 | "github.com/joho/godotenv" 19 | ) 20 | 21 | type IssuingAuthorization2 struct { 22 | Specs string `json:"specs"` 23 | Content string `json:"content"` 24 | Signature string `json:"signature"` 25 | } 26 | 27 | func loadEnv2() { 28 | err := godotenv.Load() 29 | if err != nil { 30 | log.Fatal("Cannot load '.env' file, terminating.") 31 | } 32 | } 33 | 34 | func getEnv2(evar string) string { 35 | val := os.Getenv(evar) 36 | if val == "" { 37 | log.Fatalf("[MISSING EVAR] %v\n", evar) 38 | os.Exit(1) 39 | } 40 | return val 41 | } 42 | 43 | func main() { 44 | loadEnv2() 45 | PRIVATE_OWNER_SIGNING_KEY := getEnv2("PRIVATE_OWNER_SIGNING_KEY") 46 | PRIVATE_VERIFIER_SIGNING_KEY := getEnv2("PRIVATE_VERIFIER_SIGNING_KEY") 47 | 48 | sharing_auth := apitypes.TypedData{ 49 | Domain: apitypes.TypedDataDomain{ 50 | Name: models.PROTOCOL_NAME, 51 | Version: models.PROTOCOL_VERSION, 52 | ChainId: math.NewHexOrDecimal256(1), 53 | }, 54 | PrimaryType: "Main", 55 | Types: apitypes.Types{ 56 | "EIP712Domain": []apitypes.Type{ 57 | { 58 | Name: "name", 59 | Type: "string", 60 | }, 61 | { 62 | Name: "chainId", 63 | Type: "uint256", 64 | }, 65 | { 66 | Name: "version", 67 | Type: "string", 68 | }, 69 | }, 70 | "Main": []apitypes.Type{ 71 | { 72 | Name: "specs", 73 | Type: "string", 74 | }, 75 | { 76 | Name: "shared_at", 77 | Type: "uint64", 78 | }, 79 | { 80 | Name: "attributes", 81 | Type: "Attributes", 82 | }, 83 | { 84 | Name: "verifier", 85 | Type: "Verifier", 86 | }, 87 | { 88 | Name: "owner", 89 | Type: "Owner", 90 | }, 91 | }, 92 | "Owner": []apitypes.Type{ 93 | { 94 | Name: "id", 95 | Type: "string", 96 | }, 97 | { 98 | Name: "public_address", 99 | Type: "address", 100 | }, 101 | { 102 | Name: "chain", 103 | Type: "string", 104 | }, 105 | }, 106 | "Verifier": []apitypes.Type{ 107 | { 108 | Name: "id", 109 | Type: "string", 110 | }, 111 | { 112 | Name: "public_address", 113 | Type: "address", 114 | }, 115 | { 116 | Name: "chain", 117 | Type: "string", 118 | }, 119 | }, 120 | "Attributes": []apitypes.Type{ 121 | { 122 | Name: "document_front", 123 | Type: "string", 124 | }, 125 | { 126 | Name: "firstname", 127 | Type: "string", 128 | }, 129 | }, 130 | }, 131 | Message: apitypes.TypedDataMessage{ 132 | "specs": "anima:schema:sharing/authorization@1.0.0", 133 | "shared_at": uint64(time.Now().Unix()), 134 | "attributes": apitypes.TypedDataMessage{ 135 | "document_front": "anima:credential:7aeaffeb4913b428fa357f55d54d70b7bf0678a7282227193181b5d8065de5f3", 136 | "firstname": "anima:credential:4403186310d2cb3c15501d5cf216eacc00a479c6ade49eb23968a729b36f7cdc", 137 | }, 138 | "owner": apitypes.TypedDataMessage{ 139 | "id": "anima:owner:0x017f912f75c4140699606Ddb8418Ec944AAbCEBA", 140 | "public_address": "0x017f912f75c4140699606Ddb8418Ec944AAbCEBA", 141 | "chain": "ETH", 142 | }, 143 | "verifier": apitypes.TypedDataMessage{ 144 | "id": "anima:verifier:syn_slash_bank@1.0.0", 145 | "public_address": "0x168FE97dCAd13e39838FB0e543d8A221904cE5BA", 146 | "chain": "ETH", 147 | }, 148 | }, 149 | } 150 | 151 | challenge, err := json.Marshal(sharing_auth) 152 | if err != nil { 153 | log.Fatal("Error while transforming authorization in json") 154 | os.Exit(1) 155 | } 156 | 157 | challengeHash, _ := evm.GetEIP712Message(challenge) 158 | 159 | privateKey, _ := crypto.HexToECDSA(PRIVATE_OWNER_SIGNING_KEY) 160 | signature, err := crypto.Sign(challengeHash, privateKey) 161 | if err != nil { 162 | fmt.Printf("%v\n", err) 163 | os.Exit(1) 164 | } 165 | hexSignature := "0x" + hex.EncodeToString(signature) 166 | 167 | base64Challenge := base64.StdEncoding.EncodeToString(challenge) 168 | 169 | result := IssuingAuthorization2{ 170 | Specs: "anima:schema:sharing/authorization/eip712@1.0.0", 171 | Content: base64Challenge, 172 | Signature: hexSignature, 173 | } 174 | 175 | finalAuthorization := make(map[string]interface{}) 176 | finalAuthorization["authorization"] = result 177 | 178 | jsonResult, _ := json.Marshal(finalAuthorization) 179 | message := make(map[string]interface{}) 180 | 181 | message["content"] = animaCrypto.HashSHA256(jsonResult) 182 | 183 | sigRequest := apitypes.TypedData{ 184 | Domain: apitypes.TypedDataDomain{ 185 | Name: models.PROTOCOL_NAME, 186 | Version: models.PROTOCOL_VERSION, 187 | ChainId: math.NewHexOrDecimal256(1), 188 | }, 189 | PrimaryType: "Main", 190 | Types: apitypes.Types{ 191 | "EIP712Domain": []apitypes.Type{ 192 | { 193 | Name: "name", 194 | Type: "string", 195 | }, 196 | { 197 | Name: "chainId", 198 | Type: "uint256", 199 | }, 200 | { 201 | Name: "version", 202 | Type: "string", 203 | }, 204 | }, 205 | "Main": []apitypes.Type{ 206 | { 207 | Name: "content", 208 | Type: "string", 209 | }, 210 | }, 211 | }, 212 | Message: message, 213 | } 214 | 215 | c, err := json.Marshal(sigRequest) 216 | if err != nil { 217 | return 218 | } 219 | 220 | verifierPrivateKey, _ := crypto.HexToECDSA(PRIVATE_VERIFIER_SIGNING_KEY) 221 | digest, err := evm.GetEIP712Message(c) 222 | if err != nil { 223 | return 224 | } 225 | 226 | verifierSignature, err := crypto.Sign(digest, verifierPrivateKey) 227 | if err != nil { 228 | return 229 | } 230 | 231 | fmt.Println(string(jsonResult)) 232 | fmt.Println("0x" + hex.EncodeToString(verifierSignature)) 233 | } 234 | -------------------------------------------------------------------------------- /core/issuing_authorization.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "encoding/base64" 5 | "encoding/json" 6 | 7 | "github.com/anima-protocol/anima-go/chains" 8 | cosmos "github.com/anima-protocol/anima-go/chains/cosmos/signature" 9 | "github.com/anima-protocol/anima-go/chains/elrond" 10 | "github.com/anima-protocol/anima-go/chains/evm" 11 | starknet "github.com/anima-protocol/anima-go/chains/starknet/signature" 12 | "github.com/anima-protocol/anima-go/models" 13 | "github.com/anima-protocol/anima-go/protocol" 14 | ) 15 | 16 | func GetChainSignatureFuncIssuing(authorization *models.IssuingAuthorization) func(string, []byte, string) error { 17 | switch authorization.Owner.Chain { 18 | case chains.EVM: 19 | return evm.VerifyPersonalSignature 20 | case chains.ELROND: 21 | return elrond.VerifyPersonalSignature 22 | case chains.MULTIVERSX: 23 | return elrond.VerifyPersonalSignature 24 | case chains.COSMOS: 25 | return cosmos.VerifyPersonalSignature 26 | } 27 | 28 | return evm.VerifyPersonalSignature 29 | } 30 | 31 | func GetIssuingAuthorization(document *protocol.IssDocument, starknetRpcProvider string) (*models.IssuingAuthorization, error) { 32 | encodedContent := document.Authorization.Content 33 | signature := document.Authorization.Signature 34 | 35 | content, err := base64.StdEncoding.DecodeString(encodedContent) 36 | if err != nil { 37 | return nil, err 38 | } 39 | 40 | authorization := models.IssuingAuthorization{} 41 | if err := json.Unmarshal(content, &authorization); err != nil { 42 | return nil, err 43 | } 44 | 45 | if authorization.Owner.Chain == chains.STARKNET { 46 | err = starknet.VerifyPersonalSignature(authorization.Owner.PublicAddress, content, signature, starknetRpcProvider) 47 | } else { 48 | err = GetChainSignatureFuncIssuing(&authorization)(authorization.Owner.PublicAddress, content, signature) 49 | if err != nil { 50 | return nil, err 51 | } 52 | } 53 | 54 | return &authorization, nil 55 | } 56 | -------------------------------------------------------------------------------- /core/sign_attributes.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "bytes" 5 | "encoding/base64" 6 | "encoding/json" 7 | "fmt" 8 | "strings" 9 | "time" 10 | 11 | "github.com/anima-protocol/anima-go/chains/evm" 12 | "github.com/anima-protocol/anima-go/crypto" 13 | "github.com/anima-protocol/anima-go/models" 14 | "github.com/anima-protocol/anima-go/protocol" 15 | ) 16 | 17 | func SignIssuing(anima *models.Protocol, issuer *protocol.AnimaIssuer, request *protocol.IssueDocumentRequest, signingFunc func([]byte) (string, error)) (*protocol.IssueDocumentRequest, error) { 18 | issuingAuthorization, err := GetIssuingAuthorization(request.Document, anima.StarknetRpcURL) 19 | if err != nil { 20 | return nil, err 21 | } 22 | 23 | if issuingAuthorization.PublicKeyEncryption != "" { 24 | request.Document.EncryptionKey = issuingAuthorization.PublicKeyEncryption 25 | } 26 | 27 | // Sign Proof 28 | proofContent, err := base64.StdEncoding.DecodeString(request.Proof.Content) 29 | if err != nil { 30 | return nil, err 31 | } 32 | 33 | proofContentBytes := new(bytes.Buffer) 34 | err = json.Compact(proofContentBytes, proofContent) 35 | if err != nil { 36 | return nil, err 37 | } 38 | 39 | switch anima.Chain { 40 | case models.CHAIN_ETH: 41 | proofSignature, err := evm.SignBytes(proofContentBytes.Bytes(), signingFunc) 42 | if err != nil { 43 | return nil, err 44 | } 45 | 46 | request.Proof.Signature = "0x" + proofSignature 47 | } 48 | 49 | proofId := fmt.Sprintf("anima:proof:%s", crypto.HashSHA256(proofContentBytes.Bytes())) 50 | 51 | owner := &protocol.AnimaOwner{ 52 | Id: issuingAuthorization.Owner.ID, 53 | PublicAddress: issuingAuthorization.Owner.PublicAddress, 54 | Chain: issuingAuthorization.Owner.Chain, 55 | } 56 | 57 | request.Document.Owner = owner 58 | 59 | issuedAt := time.Now().Unix() 60 | // Sign Attributes 61 | for name := range request.Attributes { 62 | attrType := request.Document.Attributes[name].Content.Type 63 | 64 | request.Attributes[name].Content = &protocol.IssDocumentAttributeContent{ 65 | Type: attrType, 66 | Name: request.Document.Attributes[name].Content.Name, 67 | Format: request.Document.Attributes[name].Content.Format, 68 | Authorization: request.Document.Authorization, 69 | Owner: owner, 70 | } 71 | contentHashes := []string{} 72 | contentHash := "" 73 | 74 | if strings.HasSuffix(attrType, "[]") { 75 | request.Attributes[name].Content.Values = request.Document.Attributes[name].Content.Values 76 | 77 | if strings.HasPrefix(attrType, "file") { 78 | contentHashes = request.Document.Attributes[name].Content.Values 79 | } else { 80 | for _, value := range request.Document.Attributes[name].Content.Values { 81 | contentHashes = append(contentHashes, crypto.HashSHA256Str(value)) 82 | } 83 | } 84 | } else { 85 | request.Attributes[name].Content.Value = request.Document.Attributes[name].Content.Value 86 | if request.Attributes[name].Content.Type == "file" { 87 | contentHash = request.Document.Attributes[name].Content.Value 88 | } else { 89 | contentHash = crypto.HashSHA256Str(request.Document.Attributes[name].Content.Value) 90 | } 91 | } 92 | 93 | attrBytes, err := json.Marshal(request.Attributes[name].Content) 94 | if err != nil { 95 | return nil, err 96 | } 97 | 98 | attrContentBytes := new(bytes.Buffer) 99 | err = json.Compact(attrContentBytes, attrBytes) 100 | if err != nil { 101 | return nil, err 102 | } 103 | 104 | request.Attributes[name].Credential.Content = &protocol.IssAttributeCredentialContent{ 105 | IssuedAt: issuedAt, 106 | ExpiresAt: request.Document.ExpiresAt, 107 | Owner: owner, 108 | Issuer: issuer, 109 | Attribute: &protocol.IssAttributeCredentialContentAttribute{ 110 | Specs: "anima:schema:attribute@1.0.0", 111 | Id: fmt.Sprintf("anima:attribute:%s", crypto.HashSHA256(attrContentBytes.Bytes())), 112 | Hash: contentHash, 113 | Name: name, 114 | }, 115 | Proof: &protocol.IssAttributeCredentialContentProof{ 116 | Specs: request.Proof.Specs, 117 | Id: proofId, 118 | }, 119 | Authorization: &protocol.IssAttributeCredentialContentAuthorization{ 120 | Content: request.Document.Authorization.Content, 121 | Signature: request.Document.Authorization.Signature, 122 | }, 123 | } 124 | if strings.HasSuffix(attrType, "[]") { 125 | request.Attributes[name].Credential.Content.Attribute.Hashes = contentHashes 126 | } else { 127 | request.Attributes[name].Credential.Content.Attribute.Hash = contentHash 128 | } 129 | 130 | request.Document.Attributes[name].Credential = &protocol.IssDocumentAttributeCredential{ 131 | Specs: "anima:schema:credential@1.0.0", 132 | Id: fmt.Sprintf("anima:credential:%s", crypto.HashSHA256(attrContentBytes.Bytes())), 133 | } 134 | } 135 | 136 | for name := range request.Attributes { 137 | documentBytes, err := json.Marshal(request.Document) 138 | if err != nil { 139 | return nil, err 140 | } 141 | 142 | documentContentBytes := new(bytes.Buffer) 143 | err = json.Compact(documentContentBytes, documentBytes) 144 | if err != nil { 145 | return nil, err 146 | } 147 | 148 | request.Attributes[name].Credential.Content.Document = &protocol.IssAttributeCredentialContentDocument{ 149 | Specs: request.Document.Specs, 150 | Id: fmt.Sprintf("anima:document:%s", crypto.HashSHA256(documentContentBytes.Bytes())), 151 | } 152 | 153 | switch anima.Chain { 154 | case models.CHAIN_ETH: 155 | signature, err := evm.SignInterfaceData(request.Attributes[name].Credential.Content, signingFunc) 156 | if err != nil { 157 | return nil, err 158 | } 159 | 160 | request.Attributes[name].Credential.Signature = "0x" + signature 161 | } 162 | } 163 | 164 | return request, nil 165 | } 166 | -------------------------------------------------------------------------------- /crypto/hash.go: -------------------------------------------------------------------------------- 1 | package crypto 2 | 3 | import ( 4 | "crypto/sha256" 5 | "encoding/hex" 6 | ) 7 | 8 | func HashSHA256Bytes(content []byte) []byte { 9 | h := sha256.New() 10 | h.Write(content) 11 | sum := h.Sum(nil) 12 | return sum 13 | } 14 | 15 | func HashSHA256(content []byte) string { 16 | return hex.EncodeToString(HashSHA256Bytes(content)) 17 | } 18 | 19 | func HashSHA256Str(str string) string { 20 | content := []byte(str) 21 | return hex.EncodeToString(HashSHA256Bytes(content)) 22 | } 23 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/anima-protocol/anima-go 2 | 3 | go 1.23.1 4 | 5 | toolchain go1.23.4 6 | 7 | require ( 8 | github.com/NethermindEth/juno v0.12.2 9 | github.com/NethermindEth/starknet.go v0.7.3 10 | github.com/btcsuite/btcutil v1.0.2 11 | github.com/ethereum/go-ethereum v1.14.8 12 | github.com/joho/godotenv v1.4.0 13 | golang.org/x/crypto v0.26.0 14 | google.golang.org/grpc v1.66.0 15 | google.golang.org/protobuf v1.34.2 16 | ) 17 | 18 | require ( 19 | github.com/btcsuite/btcd/btcec/v2 v2.3.4 20 | github.com/deckarep/golang-set/v2 v2.6.0 // indirect 21 | github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect 22 | github.com/go-ole/go-ole v1.3.0 // indirect 23 | github.com/gorilla/websocket v1.5.3 // indirect 24 | github.com/shirou/gopsutil v3.21.11+incompatible // indirect 25 | github.com/yusufpapurcu/wmi v1.2.4 // indirect 26 | google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 // indirect 27 | ) 28 | 29 | require ( 30 | github.com/Microsoft/go-winio v0.6.2 // indirect 31 | github.com/bits-and-blooms/bitset v1.14.2 // indirect 32 | github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect 33 | github.com/consensys/bavard v0.1.13 // indirect 34 | github.com/consensys/gnark-crypto v0.13.0 // indirect 35 | github.com/crate-crypto/go-kzg-4844 v1.1.0 // indirect 36 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect 37 | github.com/ethereum/c-kzg-4844 v1.0.0 // indirect 38 | github.com/fxamacker/cbor/v2 v2.7.0 // indirect 39 | github.com/holiman/uint256 v1.3.1 // indirect 40 | github.com/mmcloughlin/addchain v0.4.0 // indirect 41 | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect 42 | github.com/stretchr/testify v1.9.0 // indirect 43 | github.com/supranational/blst v0.3.11 // indirect 44 | github.com/tklauser/go-sysconf v0.3.13 // indirect 45 | github.com/tklauser/numcpus v0.7.0 // indirect 46 | github.com/x448/float16 v0.8.4 // indirect 47 | golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa // indirect 48 | golang.org/x/net v0.28.0 // indirect 49 | golang.org/x/sync v0.8.0 // indirect 50 | golang.org/x/sys v0.24.0 // indirect 51 | golang.org/x/text v0.17.0 // indirect 52 | gopkg.in/yaml.v3 v3.0.1 // indirect 53 | rsc.io/tmplfunc v0.0.3 // indirect 54 | ) 55 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/DataDog/zstd v1.5.6-0.20230824185856-869dae002e5e h1:ZIWapoIRN1VqT8GR8jAwb1Ie9GyehWjVcGh32Y2MznE= 2 | github.com/DataDog/zstd v1.5.6-0.20230824185856-869dae002e5e/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= 3 | github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= 4 | github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= 5 | github.com/NethermindEth/juno v0.12.2 h1:GnQUgqMCA93EO7KROlXI5AdXQ9IBvcDP2PEYFr3fQIY= 6 | github.com/NethermindEth/juno v0.12.2/go.mod h1:PlxXUUGgzFVRIiSDrLo/jrEtAPUIHpFAylChtoH3wK4= 7 | github.com/NethermindEth/starknet.go v0.7.3 h1:IM7w+0n/4ftLDTAnHMnJ1veUDq0wb3RGDLUxxWWmdI4= 8 | github.com/NethermindEth/starknet.go v0.7.3/go.mod h1:qDb22jUUbOT5hWC4mgyuFp5q40JIyHfVo13XIB0OLy4= 9 | github.com/VictoriaMetrics/fastcache v1.12.2 h1:N0y9ASrJ0F6h0QaC3o6uJb3NIZ9VKLjCM7NQbSmF7WI= 10 | github.com/VictoriaMetrics/fastcache v1.12.2/go.mod h1:AmC+Nzz1+3G2eCPapF6UcsnkThDcMsQicp4xDukwJYI= 11 | github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= 12 | github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= 13 | github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= 14 | github.com/bits-and-blooms/bitset v1.14.2 h1:YXVoyPndbdvcEVcseEovVfp0qjJp7S+i5+xgp/Nfbdc= 15 | github.com/bits-and-blooms/bitset v1.14.2/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= 16 | github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= 17 | github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ= 18 | github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= 19 | github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= 20 | github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= 21 | github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= 22 | github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= 23 | github.com/btcsuite/btcutil v1.0.2 h1:9iZ1Terx9fMIOtq1VrwdqfsATL9MC2l8ZrUY6YZ2uts= 24 | github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= 25 | github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= 26 | github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= 27 | github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= 28 | github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= 29 | github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= 30 | github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= 31 | github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 32 | github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I= 33 | github.com/cockroachdb/errors v1.11.3/go.mod h1:m4UIW4CDjx+R5cybPsNrRbreomiFqt8o1h1wUVazSd8= 34 | github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce h1:giXvy4KSc/6g/esnpM7Geqxka4WSqI1SZc7sMJFd3y4= 35 | github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M= 36 | github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= 37 | github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= 38 | github.com/cockroachdb/pebble v1.1.2 h1:CUh2IPtR4swHlEj48Rhfzw6l/d0qA31fItcIszQVIsA= 39 | github.com/cockroachdb/pebble v1.1.2/go.mod h1:4exszw1r40423ZsmkG/09AFEG83I0uDgfujJdbL6kYU= 40 | github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= 41 | github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= 42 | github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= 43 | github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= 44 | github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= 45 | github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= 46 | github.com/consensys/gnark-crypto v0.13.0 h1:VPULb/v6bbYELAPTDFINEVaMTTybV5GLxDdcjnS+4oc= 47 | github.com/consensys/gnark-crypto v0.13.0/go.mod h1:wKqwsieaKPThcFkHe0d0zMsbHEUWFmZcG7KBCse210o= 48 | github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c h1:uQYC5Z1mdLRPrZhHjHxufI8+2UG/i25QG92j0Er9p6I= 49 | github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c/go.mod h1:geZJZH3SzKCqnz5VT0q/DyIG/tvu/dZk+VIfXicupJs= 50 | github.com/crate-crypto/go-kzg-4844 v1.1.0 h1:EN/u9k2TF6OWSHrCCDBBU6GLNMq88OspHHlMnHfoyU4= 51 | github.com/crate-crypto/go-kzg-4844 v1.1.0/go.mod h1:JolLjpSff1tCCJKaJx4psrlEdlXuJEC996PL3tTAFks= 52 | github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 53 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= 54 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 55 | github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM= 56 | github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= 57 | github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= 58 | github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= 59 | github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= 60 | github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= 61 | github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA= 62 | github.com/ethereum/c-kzg-4844 v1.0.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= 63 | github.com/ethereum/go-ethereum v1.14.8 h1:NgOWvXS+lauK+zFukEvi85UmmsS/OkV0N23UZ1VTIig= 64 | github.com/ethereum/go-ethereum v1.14.8/go.mod h1:TJhyuDq0JDppAkFXgqjwpdlQApywnu/m10kFPxh8vvs= 65 | github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0 h1:KrE8I4reeVvf7C1tm8elRjj4BdscTYzz/WAbYyf/JI4= 66 | github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0/go.mod h1:D9AJLVXSyZQXJQVk8oh1EwjISE+sJTn2duYIZC0dy3w= 67 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 68 | github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= 69 | github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= 70 | github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps= 71 | github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= 72 | github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= 73 | github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= 74 | github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= 75 | github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= 76 | github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= 77 | github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= 78 | github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= 79 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 80 | github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= 81 | github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 82 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 83 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 84 | github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= 85 | github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= 86 | github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 87 | github.com/holiman/uint256 v1.3.1 h1:JfTzmih28bittyHM8z360dCjIA9dbPIBlcTI6lmctQs= 88 | github.com/holiman/uint256 v1.3.1/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= 89 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= 90 | github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= 91 | github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= 92 | github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= 93 | github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= 94 | github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= 95 | github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= 96 | github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= 97 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= 98 | github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= 99 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 100 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 101 | github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= 102 | github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= 103 | github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= 104 | github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= 105 | github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= 106 | github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= 107 | github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= 108 | github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= 109 | github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= 110 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= 111 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= 112 | github.com/nsf/jsondiff v0.0.0-20210926074059-1e845ec5d249 h1:NHrXEjTNQY7P0Zfx1aMrNhpgxHmow66XQtm0aQLY0AE= 113 | github.com/nsf/jsondiff v0.0.0-20210926074059-1e845ec5d249/go.mod h1:mpRZBD8SJ55OIICQ3iWH0Yz3cjzA61JdqMLoWXeB2+8= 114 | github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= 115 | github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= 116 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 117 | github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 118 | github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 119 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 120 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 121 | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= 122 | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 123 | github.com/prometheus/client_golang v1.20.2 h1:5ctymQzZlyOON1666svgwn3s6IKWgfbjsejTMiXIyjg= 124 | github.com/prometheus/client_golang v1.20.2/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= 125 | github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= 126 | github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= 127 | github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= 128 | github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= 129 | github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= 130 | github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= 131 | github.com/rivo/uniseg v0.4.2 h1:YwD0ulJSJytLpiaWua0sBDusfsCZohxjxzVTYjwxfV8= 132 | github.com/rivo/uniseg v0.4.2/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= 133 | github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= 134 | github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= 135 | github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= 136 | github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= 137 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 138 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 139 | github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= 140 | github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 141 | github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4= 142 | github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= 143 | github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= 144 | github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= 145 | github.com/tklauser/go-sysconf v0.3.13 h1:GBUpcahXSpR2xN01jhkNAbTLRk2Yzgggk8IM08lq3r4= 146 | github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5IJePewFCGVEa0= 147 | github.com/tklauser/numcpus v0.7.0 h1:yjuerZP127QG9m5Zh/mSO4wqurYil27tHrqwRoRjpr4= 148 | github.com/tklauser/numcpus v0.7.0/go.mod h1:bb6dMVcj8A42tSE7i32fsIUCbQNllK5iDguyOZRUzAY= 149 | github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= 150 | github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= 151 | github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= 152 | github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= 153 | go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= 154 | go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= 155 | go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= 156 | go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= 157 | golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 158 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 159 | golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 160 | golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= 161 | golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= 162 | golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI= 163 | golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ= 164 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 165 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 166 | golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= 167 | golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= 168 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 169 | golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= 170 | golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 171 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 172 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 173 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 174 | golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 175 | golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 176 | golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= 177 | golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 178 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 179 | golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= 180 | golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= 181 | google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 h1:1GBuWVLM/KMVUv1t1En5Gs+gFZCNd360GGb4sSxtrhU= 182 | google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= 183 | google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c= 184 | google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= 185 | google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= 186 | google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= 187 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 188 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 189 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 190 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 191 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 192 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 193 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 194 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 195 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 196 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 197 | rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= 198 | rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= 199 | -------------------------------------------------------------------------------- /models/anima.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | type Protocol struct { 4 | Network string `json:"network"` 5 | Chain string `json:"chain"` 6 | StarknetRpcURL string `json:"starknet_rpc_url"` 7 | SigningFunc func([]byte) (string, error) `json:"signing_func"` 8 | Secure bool `json:"secure"` 9 | } 10 | 11 | type AnimaOwner struct { 12 | ID string `json:"id"` 13 | PublicAddress string `json:"public_address"` 14 | Chain string `json:"chain"` 15 | PublicKeyEncryption string `json:"public_key_encryption,omitempty"` 16 | } 17 | 18 | type AnimaIssuer struct { 19 | ID string `json:"id"` 20 | PublicAddress string `json:"public_address"` 21 | Chain string `json:"chain"` 22 | } 23 | 24 | type AnimaVerifier struct { 25 | ID string `json:"id"` 26 | PublicAddress string `json:"public_address"` 27 | Chain string `json:"chain"` 28 | } 29 | 30 | type AnimaProtocol struct { 31 | ID string `json:"id"` 32 | PublicAddress string `json:"public_address"` 33 | Chain string `json:"chain"` 34 | } 35 | -------------------------------------------------------------------------------- /models/authorization.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | type IssuingAuthorization struct { 4 | Specs string `json:"specs"` 5 | PublicKeyEncryption string `json:"public_key_encryption,omitempty"` 6 | Nonce string `json:"nonce,omitempty"` 7 | RequestedAt int64 `json:"requested_at"` 8 | Fields map[string]interface{} `json:"fields"` 9 | Attributes map[string]bool `json:"attributes"` 10 | Owner AnimaOwner `json:"owner"` 11 | Issuer AnimaIssuer `json:"issuer"` 12 | } 13 | -------------------------------------------------------------------------------- /models/const.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | const ( 4 | /* PROTOCOL */ 5 | PROTOCOL_NAME = "anima" 6 | PROTOCOL_VERSION = "1.0" 7 | 8 | /* NETWORK */ 9 | MAINNET = "protocol.anima.io:443" 10 | TESTNET = "protocol-tesnet.anima.io:443" 11 | 12 | /* CHAIN */ 13 | CHAIN_ETH = "ETH" 14 | CHAIN_ETH_ID = 1 15 | ) 16 | 17 | var AVAILABLE_CHAIN = []string{CHAIN_ETH} 18 | -------------------------------------------------------------------------------- /models/issue.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | type IssAttribute struct { 4 | Name string `json:"name"` 5 | Type string `json:"type"` 6 | Format string `json:"format"` 7 | Value string `json:"value"` 8 | } 9 | 10 | type IssOwner struct { 11 | ID string `json:"id"` 12 | PublicAddress string `json:"public_address"` 13 | Chain string `json:"chain"` 14 | } 15 | 16 | type IssAuthorization struct { 17 | Specs string `json:"specs"` 18 | Content string `json:"content"` 19 | Signature string `json:"signature"` 20 | } 21 | 22 | type IssDocument struct { 23 | Specs string `json:"specs"` 24 | IssuedAt string `json:"issued_at"` 25 | ExpiresAt string `json:"expires_at"` 26 | Attributes map[string]IssAttribute `json:"attributes"` 27 | Owner IssOwner `json:"owner"` 28 | IssuingAuthorization IssAuthorization `json:"issuing_authorization"` 29 | } 30 | 31 | type IssAttributeCredential struct { 32 | Value interface{} `json:"value"` 33 | Credential IssCredential `json:"credential"` 34 | } 35 | 36 | type IssCredentialSource struct { 37 | ID string `json:"id"` 38 | Specs string `json:"specs"` 39 | } 40 | 41 | type IssCredential struct { 42 | Content IssCredentialContent `json:"content"` 43 | Signature string `json:"signature"` 44 | } 45 | 46 | type IssCredentialContent struct { 47 | IssuedAt string `json:"issued_at"` 48 | ExpiresAt string `json:"expires_at"` 49 | Source IssCredentialSource `json:"source"` 50 | Owner IssOwner `json:"owner"` 51 | Name string `json:"name"` 52 | Type string `json:"type"` 53 | Format string `json:"format"` 54 | Hash string `json:"hash"` 55 | } 56 | 57 | type IssProof struct { 58 | Specs string `json:"specs"` 59 | Content string `json:"content"` 60 | Signature string `json:"signature"` 61 | } 62 | 63 | type IssueRequest struct { 64 | Document IssDocument `json:"document"` 65 | Attributes map[string]IssAttributeCredential `json:"attributes"` 66 | Proof IssProof `json:"proof"` 67 | } 68 | -------------------------------------------------------------------------------- /models/std_sign_doc.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | type Coin struct { 4 | Denom string `json:"denom"` 5 | Amount string `json:"amount"` 6 | } 7 | 8 | type StdFee struct { 9 | Amount []Coin `json:"amount"` 10 | Gas string `json:"gas"` 11 | Payer *string `json:"payer,omitempty"` 12 | Granter *string `json:"granter,omitempty"` 13 | FeePayer *string `json:"feePayer,omitempty"` 14 | } 15 | 16 | type MsgSignData struct { 17 | Data string `json:"data"` 18 | Signer string `json:"signer"` 19 | } 20 | 21 | type Msg struct { 22 | Type string `json:"type"` 23 | Value MsgSignData `json:"value"` 24 | } 25 | 26 | type StdSignDoc struct { 27 | AccountNumber string `json:"account_number"` 28 | ChainId string `json:"chain_id"` 29 | Fee StdFee `json:"fee"` 30 | Memo string `json:"memo"` 31 | Msgs []Msg `json:"msgs"` 32 | Sequence string `json:"sequence"` 33 | TimeoutHeight *string `json:"timeout_height,omitempty"` 34 | } 35 | -------------------------------------------------------------------------------- /models/verifier.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | type RegisterVerifierRequest struct { 4 | Id string `json:"id"` 5 | PublicAddress string `json:"public_address"` 6 | Chain string `json:"chain"` 7 | } 8 | -------------------------------------------------------------------------------- /protocol/endpoints.go: -------------------------------------------------------------------------------- 1 | package protocol 2 | 3 | import ( 4 | context "context" 5 | "errors" 6 | 7 | "github.com/anima-protocol/anima-go/chains/evm" 8 | "github.com/anima-protocol/anima-go/models" 9 | "github.com/anima-protocol/anima-go/utils" 10 | "google.golang.org/grpc/metadata" 11 | ) 12 | 13 | func Issue(anima *models.Protocol, req *IssueDocumentRequest) (*IssueDocumentResponse, error) { 14 | config := &Config{Secure: anima.Secure} 15 | err := Init(config, anima) 16 | if err != nil { 17 | return nil, err 18 | } 19 | 20 | if !utils.InArray(anima.Chain, []string{"ETH"}) { 21 | return nil, errors.New("unsupported chain") 22 | } 23 | 24 | signature, err := evm.SignInterfaceData(req, anima.SigningFunc) 25 | if err != nil { 26 | return nil, err 27 | } 28 | 29 | header := metadata.New(map[string]string{"signature": signature, "chain": anima.Chain}) 30 | ctx := metadata.NewOutgoingContext(context.Background(), header) 31 | 32 | response, err := client.Issue(ctx, req) 33 | 34 | if err != nil { 35 | return nil, err 36 | } 37 | return response, nil 38 | } 39 | 40 | func Verify(anima *models.Protocol, req *VerifyRequest) (*VerifyResponse, error) { 41 | config := &Config{Secure: anima.Secure} 42 | err := Init(config, anima) 43 | if err != nil { 44 | return &VerifyResponse{}, err 45 | } 46 | 47 | if !utils.InArray(anima.Chain, []string{"ETH"}) { 48 | return &VerifyResponse{}, errors.New("unsupported chain") 49 | } 50 | 51 | signature, err := evm.SignInterfaceData(req, anima.SigningFunc) 52 | if err != nil { 53 | return &VerifyResponse{}, err 54 | } 55 | 56 | header := metadata.New(map[string]string{"signature": signature, "chain": anima.Chain}) 57 | ctx := metadata.NewOutgoingContext(context.Background(), header) 58 | 59 | res, err := client.Verify(ctx, req) 60 | if err != nil { 61 | return &VerifyResponse{}, err 62 | } 63 | 64 | return res, nil 65 | } 66 | 67 | func RegisterVerifier(anima *models.Protocol, req *RegisterVerifierRequest) (*RegisterVerifierResponse, error) { 68 | config := &Config{Secure: anima.Secure} 69 | err := Init(config, anima) 70 | if err != nil { 71 | return &RegisterVerifierResponse{}, err 72 | } 73 | 74 | if !utils.InArray(anima.Chain, []string{"ETH"}) { 75 | return &RegisterVerifierResponse{}, errors.New("unsupported chain") 76 | } 77 | 78 | signature, err := evm.SignInterfaceData(req, anima.SigningFunc) 79 | if err != nil { 80 | return &RegisterVerifierResponse{}, err 81 | } 82 | 83 | header := metadata.New(map[string]string{"signature": signature, "chain": anima.Chain}) 84 | ctx := metadata.NewOutgoingContext(context.Background(), header) 85 | 86 | res, err := client.RegisterVerifier(ctx, req) 87 | if err != nil { 88 | return &RegisterVerifierResponse{}, err 89 | } 90 | 91 | return res, nil 92 | } 93 | 94 | func RequestAction(anima *models.Protocol, req *RequestActionRequest) (*RequestActionResponse, error) { 95 | config := &Config{Secure: anima.Secure} 96 | err := Init(config, anima) 97 | if err != nil { 98 | return &RequestActionResponse{}, err 99 | } 100 | 101 | res, err := client.RequestAction(context.Background(), req) 102 | if err != nil { 103 | return &RequestActionResponse{}, err 104 | } 105 | 106 | return res, nil 107 | } 108 | 109 | func GrantTrustee(anima *models.Protocol, req *GrantTrusteeRequest) (*Empty, error) { 110 | config := &Config{Secure: anima.Secure} 111 | err := Init(config, anima) 112 | if err != nil { 113 | return &Empty{}, err 114 | } 115 | 116 | res, err := client.GrantTrustee(context.Background(), req) 117 | if err != nil { 118 | return &Empty{}, err 119 | } 120 | 121 | return res, nil 122 | } 123 | 124 | func RevokeTrustee(anima *models.Protocol, req *RevokeTrusteeRequest) (*Empty, error) { 125 | config := &Config{Secure: anima.Secure} 126 | err := Init(config, anima) 127 | if err != nil { 128 | return &Empty{}, err 129 | } 130 | 131 | res, err := client.RevokeTrustee(context.Background(), req) 132 | if err != nil { 133 | return &Empty{}, err 134 | } 135 | 136 | return res, nil 137 | } 138 | 139 | func ListTrustees(anima *models.Protocol, req *ListTrusteesRequest) (*ListTrusteesResponse, error) { 140 | config := &Config{Secure: anima.Secure} 141 | err := Init(config, anima) 142 | if err != nil { 143 | return &ListTrusteesResponse{}, err 144 | } 145 | 146 | res, err := client.ListTrustees(context.Background(), req) 147 | if err != nil { 148 | return &ListTrusteesResponse{}, err 149 | } 150 | 151 | return res, nil 152 | } 153 | 154 | func DeleteAnima(anima *models.Protocol, req *DeleteAnimaRequest) (*Empty, error) { 155 | config := &Config{Secure: anima.Secure} 156 | err := Init(config, anima) 157 | if err != nil { 158 | return &Empty{}, err 159 | } 160 | 161 | res, err := client.DeleteAnima(context.Background(), req) 162 | if err != nil { 163 | return &Empty{}, err 164 | } 165 | 166 | return res, nil 167 | } 168 | 169 | func DeleteSingleDocument(anima *models.Protocol, req *DeleteSingleDocumentRequest) (*Empty, error) { 170 | config := &Config{Secure: anima.Secure} 171 | err := Init(config, anima) 172 | if err != nil { 173 | return &Empty{}, err 174 | } 175 | 176 | res, err := client.DeleteSingleDocument(context.Background(), req) 177 | if err != nil { 178 | return &Empty{}, err 179 | } 180 | 181 | return res, nil 182 | } 183 | 184 | func CreateAnima(anima *models.Protocol, req *AnimaOwnerCreationRequest) (*Empty, error) { 185 | config := &Config{Secure: anima.Secure} 186 | err := Init(config, anima) 187 | if err != nil { 188 | return nil, err 189 | } 190 | 191 | res, err := client.CreateAnima(context.Background(), req) 192 | if err != nil { 193 | return nil, err 194 | } 195 | 196 | return res, nil 197 | } 198 | -------------------------------------------------------------------------------- /protocol/protocol.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package anima; 4 | option go_package="protocol/;protocol"; 5 | 6 | message Empty {} 7 | 8 | message IssueDocumentRequest { 9 | IssDocument document = 1; 10 | map attributes = 2; 11 | IssProof proof = 3; 12 | } 13 | 14 | message IssueDocumentResponse { 15 | string id = 1; 16 | string specs = 2; 17 | map attributes = 3; 18 | } 19 | 20 | message IssLiveness { 21 | string specs = 1; 22 | string id = 2; 23 | } 24 | 25 | message IssDocument { 26 | string specs = 1; 27 | string encryption_key = 2; 28 | int64 issued_at = 3; 29 | int64 expires_at = 4; 30 | map attributes = 5; 31 | AnimaOwner owner = 6; 32 | IssAuthorization authorization = 7; 33 | map requirements = 8; 34 | } 35 | 36 | message IssAuthorization { 37 | string content = 1; 38 | string signature = 2; 39 | } 40 | 41 | message IssDocumentAttribute { 42 | IssDocumentAttributeContent content = 1; 43 | IssDocumentAttributeCredential credential = 2; 44 | } 45 | 46 | message IssDocumentAttributeContent { 47 | string value = 1; 48 | repeated string values = 2; 49 | string type = 3; 50 | string format = 4; 51 | string name = 5; 52 | AnimaOwner owner = 6; 53 | IssAuthorization authorization = 7; 54 | } 55 | 56 | message IssDocumentAttributeCredential { 57 | string specs = 1; 58 | string id = 2; 59 | } 60 | 61 | message IssAttribute { 62 | bytes value = 1; 63 | repeated bytes values = 2; 64 | IssDocumentAttributeContent content = 3; 65 | IssAttributeCredential credential = 4; 66 | } 67 | 68 | message IssAttributeCredential { 69 | IssAttributeCredentialContent content = 1; 70 | string signature = 2; 71 | } 72 | 73 | message IssAttributeCredentialContent { 74 | int64 issued_at = 1; 75 | int64 expires_at = 2; 76 | AnimaOwner owner = 4; 77 | AnimaIssuer issuer = 5; 78 | IssAttributeCredentialContentDocument document = 6; 79 | IssAttributeCredentialContentAttribute attribute = 7; 80 | IssAttributeCredentialContentProof proof = 8; 81 | IssAttributeCredentialContentAuthorization authorization = 9; 82 | } 83 | 84 | message IssAttributeCredentialContentDocument { 85 | string id = 1; 86 | string specs = 2; 87 | } 88 | 89 | message IssAttributeCredentialContentProof { 90 | string id = 1; 91 | string specs = 2; 92 | } 93 | 94 | message IssAttributeCredentialContentAuthorization { 95 | string content = 1; 96 | string signature = 2; 97 | } 98 | 99 | message IssAttributeCredentialContentAttribute { 100 | string id = 1; 101 | string specs = 2; 102 | string name = 3; 103 | string hash = 4; 104 | repeated string hashes = 5; 105 | } 106 | 107 | message IssProof { 108 | string specs = 1; 109 | string content = 2; 110 | string signature = 3; 111 | } 112 | 113 | message VerifyRequest { 114 | SharingAuthorization authorization = 1; 115 | } 116 | 117 | message VerifyResponse { 118 | VerificationContent content = 1; 119 | string signature = 2; 120 | } 121 | 122 | message VerificationDocument { 123 | AnimaVerifier verifier = 1; 124 | AnimaOwner owner = 2; 125 | AnimaIssuer issuer = 3; 126 | AnimaProtocol protocol = 4; 127 | VerificationProof proof = 5; 128 | map credentials = 6; 129 | SharingAuthorization authorization = 7; 130 | } 131 | 132 | message VerificationContent { 133 | VerificationDocument document = 1; 134 | VerificationDocument liveness = 2; 135 | } 136 | 137 | message AnimaDocument { 138 | string id = 1; 139 | string specs = 2; 140 | } 141 | 142 | message AnimaAttribute { 143 | string id = 1; 144 | string specs = 2; 145 | } 146 | 147 | message AnimaProof { 148 | string id = 1; 149 | string specs = 2; 150 | } 151 | 152 | message AnimaCredentialAttribute { 153 | AnimaOwner owner = 1; 154 | AnimaIssuer issuer = 2; 155 | AnimaDocument document = 3; 156 | IssAttributeCredentialContentAttribute attribute = 4; 157 | AnimaProof proof = 5; 158 | int64 issued_at = 6; 159 | int64 expires_at = 7; 160 | } 161 | 162 | message SharingAuthorization { 163 | string content = 2; 164 | string signature = 3; 165 | } 166 | 167 | message VerificationProof { 168 | string specs = 1; 169 | string content = 2; 170 | string signature = 3; 171 | } 172 | 173 | message AnimaVerifier { 174 | string id = 1; 175 | string public_address = 2; 176 | string chain = 3; 177 | } 178 | 179 | message AnimaOwner { 180 | string id = 1; 181 | string public_address = 2; 182 | string chain = 3; 183 | } 184 | 185 | message AnimaProtocol { 186 | string id = 1; 187 | string public_address = 2; 188 | string chain = 3; 189 | } 190 | 191 | message AnimaIssuer { 192 | string id = 1; 193 | string public_address = 2; 194 | string chain = 3; 195 | } 196 | 197 | message RegisterVerifierRequest { 198 | string id = 1; 199 | string public_address = 2; 200 | string chain = 3; 201 | bytes logo = 4; 202 | string description = 5; 203 | string name = 6; 204 | } 205 | 206 | message RegisterVerifierResponse { 207 | string id = 1; 208 | } 209 | 210 | message GrantTrusteeRequest { 211 | string content = 2; 212 | string signature = 3; 213 | } 214 | 215 | message RevokeTrusteeRequest { 216 | string content = 2; 217 | string signature = 3; 218 | } 219 | 220 | message ListTrusteesRequest { 221 | string content = 2; 222 | string signature = 3; 223 | } 224 | 225 | message DeleteAnimaRequest { 226 | string content = 2; 227 | string signature = 3; 228 | } 229 | 230 | message DeleteSingleDocumentRequest { 231 | string content = 2; 232 | string signature = 3; 233 | } 234 | 235 | message ListTrusteesResponse { 236 | string id = 1; 237 | AnimaOwner owner = 2; 238 | AnimaProtocol protocol = 3; 239 | repeated string trusted_address = 4; 240 | } 241 | 242 | message StatusRequest {} 243 | 244 | message StatusResponse { 245 | string status = 1; 246 | uint64 uptime = 2; 247 | string version = 3; 248 | } 249 | 250 | message RequestActionRequest { 251 | string address = 1; 252 | } 253 | 254 | message RequestActionResponse { 255 | string nonce = 1; 256 | } 257 | 258 | message AnimaOwnerCreationRequest { 259 | string creation_challenge = 1; 260 | string creation_challenge_signature = 2; 261 | } 262 | 263 | service Anima { 264 | rpc Status(StatusRequest) returns (StatusResponse) {}; 265 | rpc CreateAnima(AnimaOwnerCreationRequest) returns (Empty) {}; 266 | rpc Issue(IssueDocumentRequest) returns (IssueDocumentResponse) {}; 267 | rpc Verify(VerifyRequest) returns (VerifyResponse) {}; 268 | rpc RegisterVerifier(RegisterVerifierRequest) returns (RegisterVerifierResponse) {}; 269 | rpc RequestAction(RequestActionRequest) returns (RequestActionResponse) {}; 270 | rpc GrantTrustee(GrantTrusteeRequest) returns (Empty) {}; 271 | rpc RevokeTrustee(RevokeTrusteeRequest) returns (Empty) {}; 272 | rpc ListTrustees(ListTrusteesRequest) returns (ListTrusteesResponse) {}; 273 | rpc DeleteAnima(DeleteAnimaRequest) returns (Empty) {}; 274 | rpc DeleteSingleDocument(DeleteSingleDocumentRequest) returns (Empty) {}; 275 | } 276 | -------------------------------------------------------------------------------- /protocol/protocol_grpc.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go-grpc. DO NOT EDIT. 2 | // versions: 3 | // - protoc-gen-go-grpc v1.2.0 4 | // - protoc v3.21.12 5 | // source: protocol/protocol.proto 6 | 7 | package protocol 8 | 9 | import ( 10 | context "context" 11 | grpc "google.golang.org/grpc" 12 | codes "google.golang.org/grpc/codes" 13 | status "google.golang.org/grpc/status" 14 | ) 15 | 16 | // This is a compile-time assertion to ensure that this generated file 17 | // is compatible with the grpc package it is being compiled against. 18 | // Requires gRPC-Go v1.32.0 or later. 19 | const _ = grpc.SupportPackageIsVersion7 20 | 21 | // AnimaClient is the client API for Anima service. 22 | // 23 | // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. 24 | type AnimaClient interface { 25 | Status(ctx context.Context, in *StatusRequest, opts ...grpc.CallOption) (*StatusResponse, error) 26 | CreateAnima(ctx context.Context, in *AnimaOwnerCreationRequest, opts ...grpc.CallOption) (*Empty, error) 27 | Issue(ctx context.Context, in *IssueDocumentRequest, opts ...grpc.CallOption) (*IssueDocumentResponse, error) 28 | Verify(ctx context.Context, in *VerifyRequest, opts ...grpc.CallOption) (*VerifyResponse, error) 29 | RegisterVerifier(ctx context.Context, in *RegisterVerifierRequest, opts ...grpc.CallOption) (*RegisterVerifierResponse, error) 30 | RequestAction(ctx context.Context, in *RequestActionRequest, opts ...grpc.CallOption) (*RequestActionResponse, error) 31 | GrantTrustee(ctx context.Context, in *GrantTrusteeRequest, opts ...grpc.CallOption) (*Empty, error) 32 | RevokeTrustee(ctx context.Context, in *RevokeTrusteeRequest, opts ...grpc.CallOption) (*Empty, error) 33 | ListTrustees(ctx context.Context, in *ListTrusteesRequest, opts ...grpc.CallOption) (*ListTrusteesResponse, error) 34 | DeleteAnima(ctx context.Context, in *DeleteAnimaRequest, opts ...grpc.CallOption) (*Empty, error) 35 | DeleteSingleDocument(ctx context.Context, in *DeleteSingleDocumentRequest, opts ...grpc.CallOption) (*Empty, error) 36 | } 37 | 38 | type animaClient struct { 39 | cc grpc.ClientConnInterface 40 | } 41 | 42 | func NewAnimaClient(cc grpc.ClientConnInterface) AnimaClient { 43 | return &animaClient{cc} 44 | } 45 | 46 | func (c *animaClient) Status(ctx context.Context, in *StatusRequest, opts ...grpc.CallOption) (*StatusResponse, error) { 47 | out := new(StatusResponse) 48 | err := c.cc.Invoke(ctx, "/anima.Anima/Status", in, out, opts...) 49 | if err != nil { 50 | return nil, err 51 | } 52 | return out, nil 53 | } 54 | 55 | func (c *animaClient) CreateAnima(ctx context.Context, in *AnimaOwnerCreationRequest, opts ...grpc.CallOption) (*Empty, error) { 56 | out := new(Empty) 57 | err := c.cc.Invoke(ctx, "/anima.Anima/CreateAnima", in, out, opts...) 58 | if err != nil { 59 | return nil, err 60 | } 61 | return out, nil 62 | } 63 | 64 | func (c *animaClient) Issue(ctx context.Context, in *IssueDocumentRequest, opts ...grpc.CallOption) (*IssueDocumentResponse, error) { 65 | out := new(IssueDocumentResponse) 66 | err := c.cc.Invoke(ctx, "/anima.Anima/Issue", in, out, opts...) 67 | if err != nil { 68 | return nil, err 69 | } 70 | return out, nil 71 | } 72 | 73 | func (c *animaClient) Verify(ctx context.Context, in *VerifyRequest, opts ...grpc.CallOption) (*VerifyResponse, error) { 74 | out := new(VerifyResponse) 75 | err := c.cc.Invoke(ctx, "/anima.Anima/Verify", in, out, opts...) 76 | if err != nil { 77 | return nil, err 78 | } 79 | return out, nil 80 | } 81 | 82 | func (c *animaClient) RegisterVerifier(ctx context.Context, in *RegisterVerifierRequest, opts ...grpc.CallOption) (*RegisterVerifierResponse, error) { 83 | out := new(RegisterVerifierResponse) 84 | err := c.cc.Invoke(ctx, "/anima.Anima/RegisterVerifier", in, out, opts...) 85 | if err != nil { 86 | return nil, err 87 | } 88 | return out, nil 89 | } 90 | 91 | func (c *animaClient) RequestAction(ctx context.Context, in *RequestActionRequest, opts ...grpc.CallOption) (*RequestActionResponse, error) { 92 | out := new(RequestActionResponse) 93 | err := c.cc.Invoke(ctx, "/anima.Anima/RequestAction", in, out, opts...) 94 | if err != nil { 95 | return nil, err 96 | } 97 | return out, nil 98 | } 99 | 100 | func (c *animaClient) GrantTrustee(ctx context.Context, in *GrantTrusteeRequest, opts ...grpc.CallOption) (*Empty, error) { 101 | out := new(Empty) 102 | err := c.cc.Invoke(ctx, "/anima.Anima/GrantTrustee", in, out, opts...) 103 | if err != nil { 104 | return nil, err 105 | } 106 | return out, nil 107 | } 108 | 109 | func (c *animaClient) RevokeTrustee(ctx context.Context, in *RevokeTrusteeRequest, opts ...grpc.CallOption) (*Empty, error) { 110 | out := new(Empty) 111 | err := c.cc.Invoke(ctx, "/anima.Anima/RevokeTrustee", in, out, opts...) 112 | if err != nil { 113 | return nil, err 114 | } 115 | return out, nil 116 | } 117 | 118 | func (c *animaClient) ListTrustees(ctx context.Context, in *ListTrusteesRequest, opts ...grpc.CallOption) (*ListTrusteesResponse, error) { 119 | out := new(ListTrusteesResponse) 120 | err := c.cc.Invoke(ctx, "/anima.Anima/ListTrustees", in, out, opts...) 121 | if err != nil { 122 | return nil, err 123 | } 124 | return out, nil 125 | } 126 | 127 | func (c *animaClient) DeleteAnima(ctx context.Context, in *DeleteAnimaRequest, opts ...grpc.CallOption) (*Empty, error) { 128 | out := new(Empty) 129 | err := c.cc.Invoke(ctx, "/anima.Anima/DeleteAnima", in, out, opts...) 130 | if err != nil { 131 | return nil, err 132 | } 133 | return out, nil 134 | } 135 | 136 | func (c *animaClient) DeleteSingleDocument(ctx context.Context, in *DeleteSingleDocumentRequest, opts ...grpc.CallOption) (*Empty, error) { 137 | out := new(Empty) 138 | err := c.cc.Invoke(ctx, "/anima.Anima/DeleteSingleDocument", in, out, opts...) 139 | if err != nil { 140 | return nil, err 141 | } 142 | return out, nil 143 | } 144 | 145 | // AnimaServer is the server API for Anima service. 146 | // All implementations must embed UnimplementedAnimaServer 147 | // for forward compatibility 148 | type AnimaServer interface { 149 | Status(context.Context, *StatusRequest) (*StatusResponse, error) 150 | CreateAnima(context.Context, *AnimaOwnerCreationRequest) (*Empty, error) 151 | Issue(context.Context, *IssueDocumentRequest) (*IssueDocumentResponse, error) 152 | Verify(context.Context, *VerifyRequest) (*VerifyResponse, error) 153 | RegisterVerifier(context.Context, *RegisterVerifierRequest) (*RegisterVerifierResponse, error) 154 | RequestAction(context.Context, *RequestActionRequest) (*RequestActionResponse, error) 155 | GrantTrustee(context.Context, *GrantTrusteeRequest) (*Empty, error) 156 | RevokeTrustee(context.Context, *RevokeTrusteeRequest) (*Empty, error) 157 | ListTrustees(context.Context, *ListTrusteesRequest) (*ListTrusteesResponse, error) 158 | DeleteAnima(context.Context, *DeleteAnimaRequest) (*Empty, error) 159 | DeleteSingleDocument(context.Context, *DeleteSingleDocumentRequest) (*Empty, error) 160 | mustEmbedUnimplementedAnimaServer() 161 | } 162 | 163 | // UnimplementedAnimaServer must be embedded to have forward compatible implementations. 164 | type UnimplementedAnimaServer struct { 165 | } 166 | 167 | func (UnimplementedAnimaServer) Status(context.Context, *StatusRequest) (*StatusResponse, error) { 168 | return nil, status.Errorf(codes.Unimplemented, "method Status not implemented") 169 | } 170 | func (UnimplementedAnimaServer) CreateAnima(context.Context, *AnimaOwnerCreationRequest) (*Empty, error) { 171 | return nil, status.Errorf(codes.Unimplemented, "method CreateAnima not implemented") 172 | } 173 | func (UnimplementedAnimaServer) Issue(context.Context, *IssueDocumentRequest) (*IssueDocumentResponse, error) { 174 | return nil, status.Errorf(codes.Unimplemented, "method Issue not implemented") 175 | } 176 | func (UnimplementedAnimaServer) Verify(context.Context, *VerifyRequest) (*VerifyResponse, error) { 177 | return nil, status.Errorf(codes.Unimplemented, "method Verify not implemented") 178 | } 179 | func (UnimplementedAnimaServer) RegisterVerifier(context.Context, *RegisterVerifierRequest) (*RegisterVerifierResponse, error) { 180 | return nil, status.Errorf(codes.Unimplemented, "method RegisterVerifier not implemented") 181 | } 182 | func (UnimplementedAnimaServer) RequestAction(context.Context, *RequestActionRequest) (*RequestActionResponse, error) { 183 | return nil, status.Errorf(codes.Unimplemented, "method RequestAction not implemented") 184 | } 185 | func (UnimplementedAnimaServer) GrantTrustee(context.Context, *GrantTrusteeRequest) (*Empty, error) { 186 | return nil, status.Errorf(codes.Unimplemented, "method GrantTrustee not implemented") 187 | } 188 | func (UnimplementedAnimaServer) RevokeTrustee(context.Context, *RevokeTrusteeRequest) (*Empty, error) { 189 | return nil, status.Errorf(codes.Unimplemented, "method RevokeTrustee not implemented") 190 | } 191 | func (UnimplementedAnimaServer) ListTrustees(context.Context, *ListTrusteesRequest) (*ListTrusteesResponse, error) { 192 | return nil, status.Errorf(codes.Unimplemented, "method ListTrustees not implemented") 193 | } 194 | func (UnimplementedAnimaServer) DeleteAnima(context.Context, *DeleteAnimaRequest) (*Empty, error) { 195 | return nil, status.Errorf(codes.Unimplemented, "method DeleteAnima not implemented") 196 | } 197 | func (UnimplementedAnimaServer) DeleteSingleDocument(context.Context, *DeleteSingleDocumentRequest) (*Empty, error) { 198 | return nil, status.Errorf(codes.Unimplemented, "method DeleteSingleDocument not implemented") 199 | } 200 | func (UnimplementedAnimaServer) mustEmbedUnimplementedAnimaServer() {} 201 | 202 | // UnsafeAnimaServer may be embedded to opt out of forward compatibility for this service. 203 | // Use of this interface is not recommended, as added methods to AnimaServer will 204 | // result in compilation errors. 205 | type UnsafeAnimaServer interface { 206 | mustEmbedUnimplementedAnimaServer() 207 | } 208 | 209 | func RegisterAnimaServer(s grpc.ServiceRegistrar, srv AnimaServer) { 210 | s.RegisterService(&Anima_ServiceDesc, srv) 211 | } 212 | 213 | func _Anima_Status_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 214 | in := new(StatusRequest) 215 | if err := dec(in); err != nil { 216 | return nil, err 217 | } 218 | if interceptor == nil { 219 | return srv.(AnimaServer).Status(ctx, in) 220 | } 221 | info := &grpc.UnaryServerInfo{ 222 | Server: srv, 223 | FullMethod: "/anima.Anima/Status", 224 | } 225 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 226 | return srv.(AnimaServer).Status(ctx, req.(*StatusRequest)) 227 | } 228 | return interceptor(ctx, in, info, handler) 229 | } 230 | 231 | func _Anima_CreateAnima_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 232 | in := new(AnimaOwnerCreationRequest) 233 | if err := dec(in); err != nil { 234 | return nil, err 235 | } 236 | if interceptor == nil { 237 | return srv.(AnimaServer).CreateAnima(ctx, in) 238 | } 239 | info := &grpc.UnaryServerInfo{ 240 | Server: srv, 241 | FullMethod: "/anima.Anima/CreateAnima", 242 | } 243 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 244 | return srv.(AnimaServer).CreateAnima(ctx, req.(*AnimaOwnerCreationRequest)) 245 | } 246 | return interceptor(ctx, in, info, handler) 247 | } 248 | 249 | func _Anima_Issue_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 250 | in := new(IssueDocumentRequest) 251 | if err := dec(in); err != nil { 252 | return nil, err 253 | } 254 | if interceptor == nil { 255 | return srv.(AnimaServer).Issue(ctx, in) 256 | } 257 | info := &grpc.UnaryServerInfo{ 258 | Server: srv, 259 | FullMethod: "/anima.Anima/Issue", 260 | } 261 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 262 | return srv.(AnimaServer).Issue(ctx, req.(*IssueDocumentRequest)) 263 | } 264 | return interceptor(ctx, in, info, handler) 265 | } 266 | 267 | func _Anima_Verify_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 268 | in := new(VerifyRequest) 269 | if err := dec(in); err != nil { 270 | return nil, err 271 | } 272 | if interceptor == nil { 273 | return srv.(AnimaServer).Verify(ctx, in) 274 | } 275 | info := &grpc.UnaryServerInfo{ 276 | Server: srv, 277 | FullMethod: "/anima.Anima/Verify", 278 | } 279 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 280 | return srv.(AnimaServer).Verify(ctx, req.(*VerifyRequest)) 281 | } 282 | return interceptor(ctx, in, info, handler) 283 | } 284 | 285 | func _Anima_RegisterVerifier_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 286 | in := new(RegisterVerifierRequest) 287 | if err := dec(in); err != nil { 288 | return nil, err 289 | } 290 | if interceptor == nil { 291 | return srv.(AnimaServer).RegisterVerifier(ctx, in) 292 | } 293 | info := &grpc.UnaryServerInfo{ 294 | Server: srv, 295 | FullMethod: "/anima.Anima/RegisterVerifier", 296 | } 297 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 298 | return srv.(AnimaServer).RegisterVerifier(ctx, req.(*RegisterVerifierRequest)) 299 | } 300 | return interceptor(ctx, in, info, handler) 301 | } 302 | 303 | func _Anima_RequestAction_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 304 | in := new(RequestActionRequest) 305 | if err := dec(in); err != nil { 306 | return nil, err 307 | } 308 | if interceptor == nil { 309 | return srv.(AnimaServer).RequestAction(ctx, in) 310 | } 311 | info := &grpc.UnaryServerInfo{ 312 | Server: srv, 313 | FullMethod: "/anima.Anima/RequestAction", 314 | } 315 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 316 | return srv.(AnimaServer).RequestAction(ctx, req.(*RequestActionRequest)) 317 | } 318 | return interceptor(ctx, in, info, handler) 319 | } 320 | 321 | func _Anima_GrantTrustee_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 322 | in := new(GrantTrusteeRequest) 323 | if err := dec(in); err != nil { 324 | return nil, err 325 | } 326 | if interceptor == nil { 327 | return srv.(AnimaServer).GrantTrustee(ctx, in) 328 | } 329 | info := &grpc.UnaryServerInfo{ 330 | Server: srv, 331 | FullMethod: "/anima.Anima/GrantTrustee", 332 | } 333 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 334 | return srv.(AnimaServer).GrantTrustee(ctx, req.(*GrantTrusteeRequest)) 335 | } 336 | return interceptor(ctx, in, info, handler) 337 | } 338 | 339 | func _Anima_RevokeTrustee_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 340 | in := new(RevokeTrusteeRequest) 341 | if err := dec(in); err != nil { 342 | return nil, err 343 | } 344 | if interceptor == nil { 345 | return srv.(AnimaServer).RevokeTrustee(ctx, in) 346 | } 347 | info := &grpc.UnaryServerInfo{ 348 | Server: srv, 349 | FullMethod: "/anima.Anima/RevokeTrustee", 350 | } 351 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 352 | return srv.(AnimaServer).RevokeTrustee(ctx, req.(*RevokeTrusteeRequest)) 353 | } 354 | return interceptor(ctx, in, info, handler) 355 | } 356 | 357 | func _Anima_ListTrustees_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 358 | in := new(ListTrusteesRequest) 359 | if err := dec(in); err != nil { 360 | return nil, err 361 | } 362 | if interceptor == nil { 363 | return srv.(AnimaServer).ListTrustees(ctx, in) 364 | } 365 | info := &grpc.UnaryServerInfo{ 366 | Server: srv, 367 | FullMethod: "/anima.Anima/ListTrustees", 368 | } 369 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 370 | return srv.(AnimaServer).ListTrustees(ctx, req.(*ListTrusteesRequest)) 371 | } 372 | return interceptor(ctx, in, info, handler) 373 | } 374 | 375 | func _Anima_DeleteAnima_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 376 | in := new(DeleteAnimaRequest) 377 | if err := dec(in); err != nil { 378 | return nil, err 379 | } 380 | if interceptor == nil { 381 | return srv.(AnimaServer).DeleteAnima(ctx, in) 382 | } 383 | info := &grpc.UnaryServerInfo{ 384 | Server: srv, 385 | FullMethod: "/anima.Anima/DeleteAnima", 386 | } 387 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 388 | return srv.(AnimaServer).DeleteAnima(ctx, req.(*DeleteAnimaRequest)) 389 | } 390 | return interceptor(ctx, in, info, handler) 391 | } 392 | 393 | func _Anima_DeleteSingleDocument_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 394 | in := new(DeleteSingleDocumentRequest) 395 | if err := dec(in); err != nil { 396 | return nil, err 397 | } 398 | if interceptor == nil { 399 | return srv.(AnimaServer).DeleteSingleDocument(ctx, in) 400 | } 401 | info := &grpc.UnaryServerInfo{ 402 | Server: srv, 403 | FullMethod: "/anima.Anima/DeleteSingleDocument", 404 | } 405 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 406 | return srv.(AnimaServer).DeleteSingleDocument(ctx, req.(*DeleteSingleDocumentRequest)) 407 | } 408 | return interceptor(ctx, in, info, handler) 409 | } 410 | 411 | // Anima_ServiceDesc is the grpc.ServiceDesc for Anima service. 412 | // It's only intended for direct use with grpc.RegisterService, 413 | // and not to be introspected or modified (even as a copy) 414 | var Anima_ServiceDesc = grpc.ServiceDesc{ 415 | ServiceName: "anima.Anima", 416 | HandlerType: (*AnimaServer)(nil), 417 | Methods: []grpc.MethodDesc{ 418 | { 419 | MethodName: "Status", 420 | Handler: _Anima_Status_Handler, 421 | }, 422 | { 423 | MethodName: "CreateAnima", 424 | Handler: _Anima_CreateAnima_Handler, 425 | }, 426 | { 427 | MethodName: "Issue", 428 | Handler: _Anima_Issue_Handler, 429 | }, 430 | { 431 | MethodName: "Verify", 432 | Handler: _Anima_Verify_Handler, 433 | }, 434 | { 435 | MethodName: "RegisterVerifier", 436 | Handler: _Anima_RegisterVerifier_Handler, 437 | }, 438 | { 439 | MethodName: "RequestAction", 440 | Handler: _Anima_RequestAction_Handler, 441 | }, 442 | { 443 | MethodName: "GrantTrustee", 444 | Handler: _Anima_GrantTrustee_Handler, 445 | }, 446 | { 447 | MethodName: "RevokeTrustee", 448 | Handler: _Anima_RevokeTrustee_Handler, 449 | }, 450 | { 451 | MethodName: "ListTrustees", 452 | Handler: _Anima_ListTrustees_Handler, 453 | }, 454 | { 455 | MethodName: "DeleteAnima", 456 | Handler: _Anima_DeleteAnima_Handler, 457 | }, 458 | { 459 | MethodName: "DeleteSingleDocument", 460 | Handler: _Anima_DeleteSingleDocument_Handler, 461 | }, 462 | }, 463 | Streams: []grpc.StreamDesc{}, 464 | Metadata: "protocol/protocol.proto", 465 | } 466 | -------------------------------------------------------------------------------- /protocol/server.go: -------------------------------------------------------------------------------- 1 | package protocol 2 | 3 | import ( 4 | "crypto/tls" 5 | "fmt" 6 | "time" 7 | 8 | "google.golang.org/grpc/credentials/insecure" 9 | "google.golang.org/grpc/keepalive" 10 | 11 | "github.com/anima-protocol/anima-go/models" 12 | "google.golang.org/grpc" 13 | "google.golang.org/grpc/credentials" 14 | ) 15 | 16 | var client AnimaClient 17 | 18 | type Config struct { 19 | Secure bool 20 | } 21 | 22 | // Init - Initialize New Client 23 | func Init(config *Config, protocol *models.Protocol) error { 24 | if client == nil { 25 | fmt.Printf("-> Anima Client") 26 | creds := credentials.NewTLS(&tls.Config{ 27 | InsecureSkipVerify: true, 28 | }) 29 | 30 | opts := []grpc.DialOption{ 31 | grpc.WithKeepaliveParams(keepalive.ClientParameters{ 32 | Time: 3 * time.Second, 33 | Timeout: 10 * time.Second, 34 | PermitWithoutStream: true, 35 | }), 36 | grpc.FailOnNonTempDialError(true), 37 | } 38 | 39 | if config.Secure { 40 | opts = append(opts, grpc.WithTransportCredentials(creds)) 41 | } else { 42 | opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials())) 43 | } 44 | 45 | opts = append(opts, grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(100000000))) 46 | opts = append(opts, grpc.WithDefaultCallOptions(grpc.MaxCallSendMsgSize(100000000))) 47 | 48 | fmt.Printf("-> network: %v\n", protocol.Network) 49 | cc, err := grpc.Dial(protocol.Network, opts...) 50 | if err != nil { 51 | return fmt.Errorf("could not connect to GRPC Server") 52 | } 53 | 54 | client = NewAnimaClient(cc) 55 | } 56 | 57 | return nil 58 | } 59 | -------------------------------------------------------------------------------- /utils/array.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | func InArray(str string, array []string) bool { 4 | for _, item := range array { 5 | if item == str { 6 | return true 7 | } 8 | } 9 | return false 10 | } 11 | -------------------------------------------------------------------------------- /utils/num.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "strconv" 5 | ) 6 | 7 | func StrToInt64(str string) int64 { 8 | n, err := strconv.ParseInt(str, 10, 64) 9 | if err != nil { 10 | return 0 11 | } 12 | return n 13 | } 14 | -------------------------------------------------------------------------------- /validators/protocol.go: -------------------------------------------------------------------------------- 1 | package validators 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/anima-protocol/anima-go/models" 7 | "github.com/anima-protocol/anima-go/utils" 8 | ) 9 | 10 | func ValidateProtocol(anima *models.Protocol) error { 11 | if !utils.InArray(anima.Chain, models.AVAILABLE_CHAIN) { 12 | return fmt.Errorf("chain unavailable") 13 | } 14 | return nil 15 | } 16 | --------------------------------------------------------------------------------