Skip to content

Commit

Permalink
dev: update generate timed signature script (#62)
Browse files Browse the repository at this point in the history
* update test-go

* update generate_timed_signature scripts

* add InvalidTargetFunctionHash

* add godotenv to server.go

* update generate_timed_signature script for new TimedSignature

* to avoid hardcoding constansts

* add privateKey params for generate_timed_signature script
  • Loading branch information
peaceandwhisky authored Nov 1, 2024
1 parent b05d300 commit 42e68cf
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 41 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ build-go:
go build ./src/go

test-go:
go test ./src/go/... ./test/...
go test ./src/go/... ./test/... -count=1

lint-go:
golangci-lint run
Expand Down
97 changes: 58 additions & 39 deletions scripts/utils/generate_timed_signature/main.go
Original file line number Diff line number Diff line change
@@ -1,68 +1,87 @@
package main

import (
"crypto/ecdsa"
"encoding/hex"
"fmt"
"log"
"math/big"
"os"
"strconv"
"time"

"github.com/joho/godotenv"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
)

func generateTimedSignature(validFor int64, privateKey *ecdsa.PrivateKey) (address common.Address, messageHash [32]byte, signature []byte, err error) {
address = crypto.PubkeyToAddress(privateKey.PublicKey)

// Step 1: Create the message hash
// Combine validFor timestamp and signer's address, then hash with Keccak256
messageHash = crypto.Keccak256Hash(
common.LeftPadBytes(big.NewInt(validFor).Bytes(), 8),
common.LeftPadBytes(address.Bytes(), 20),
)

// Step 2: Apply Mycel-specific prefix
// Prepend "\x19Mycel Signed Message:\n32" and hash again
prefixedMessage := fmt.Sprintf("\x19Mycel Signed Message:\n32%s", messageHash)
prefixedMessageHash := crypto.Keccak256Hash([]byte(prefixedMessage))
"github.com/mycel-labs/astraeus/src/go/framework"
impl "github.com/mycel-labs/astraeus/src/go/server"
testutil "github.com/mycel-labs/astraeus/test/utils"
)

// Step 3: Generate the signature
// Sign the prefixed message hash with the private key
signature, err = crypto.Sign(prefixedMessageHash.Bytes(), privateKey)
func main() {
err := godotenv.Load()
if err != nil {
return common.Address{}, [32]byte{}, nil, err
log.Fatalf("Error loading .env file")
}

// Adjust the v value of the signature (add 27)
// This ensures compatibility with Mycel's signature standard
signature[64] += 27
if len(os.Args) != 3 {
log.Fatalf("Usage: %s <privateKey> <targetFunction>", os.Args[0])
}

return address, messageHash, signature, nil
}
targetFunction := os.Args[2]

func main() {
if len(os.Args) != 3 {
log.Fatalf("Usage: %s <validFor> <privateKey>", os.Args[0])
var targetFunctionHash [32]byte

switch targetFunction {
case "CreateAccount":
targetFunctionHash = common.HexToHash(impl.CREATE_ACCOUNT_FUNCTION_HASH)
case "ApproveAddress":
targetFunctionHash = common.HexToHash(impl.APPROVE_ADDRESS_FUNCTION_HASH)
case "RevokeApproval":
targetFunctionHash = common.HexToHash(impl.REVOKE_APPROVAL_FUNCTION_HASH)
case "TransferAccount":
targetFunctionHash = common.HexToHash(impl.TRANSFER_ACCOUNT_FUNCTION_HASH)
case "DeleteAccount":
targetFunctionHash = common.HexToHash(impl.DELETE_ACCOUNT_FUNCTION_HASH)
case "UnlockAccount":
targetFunctionHash = common.HexToHash(impl.UNLOCK_ACCOUNT_FUNCTION_HASH)
case "Sign":
targetFunctionHash = common.HexToHash(impl.SIGN_FUNCTION_HASH)
default:
log.Fatalf("Unknown target function: %s", targetFunction)
}

validFor, err := strconv.ParseInt(os.Args[1], 10, 64)
privateKeyBytes, err := hex.DecodeString(os.Args[1])

if err != nil {
log.Fatalf("Invalid validFor value: %v", err)
log.Fatalf("failed to decode hex string: %v", err)
}
privKey, err := crypto.ToECDSA(privateKeyBytes)
if err != nil {
log.Fatalf("Failed to create private key: %v", err)
}

fr := framework.New(framework.WithCustomConfig(os.Getenv("PRIVATE_KEY"), os.Getenv("RPC_URL")))

privateKeyHex := os.Args[2]
privateKey, err := crypto.HexToECDSA(privateKeyHex)
log.Printf("Using TA_STORE_CONTRACT_ADDRESS: %s", os.Getenv("TA_STORE_CONTRACT_ADDRESS"))
taStoreContract, err := fr.Suave.BindToExistingContract(common.HexToAddress(os.Getenv("TA_STORE_CONTRACT_ADDRESS")), testutil.TAStoreContractPath)
if err != nil {
log.Fatalf("Invalid private key: %v", err)
log.Fatalf("Failed to bind to existing contract: %v", err)
}

address, messageHash, signature, err := generateTimedSignature(validFor, privateKey)
valdFor := uint64(time.Now().Unix() + 86400)

timedSignature, err := testutil.NewPbTimedSignature(taStoreContract, privKey, valdFor, targetFunctionHash)

if err != nil {
log.Fatalf("Failed to generate timed signature: %v", err)
}

fmt.Printf("Address: %x\n", address)
fmt.Printf("Message Hash: %x\n", messageHash)
fmt.Printf("Signature: %x\n", signature)
fmt.Printf("\"proof\": {\n")
fmt.Printf(" \"validFor\": %d,\n", valdFor)
fmt.Printf(" \"messageHash\": \"%s\",\n", timedSignature.MessageHash)
fmt.Printf(" \"signature\": \"%s\",\n", timedSignature.Signature)
fmt.Printf(" \"signer\": \"%s\",\n", timedSignature.Signer)
fmt.Printf(" \"nonce\": %d,\n", timedSignature.Nonce)
fmt.Printf(" \"target_function_hash\": \"%s\"\n", timedSignature.TargetFunctionHash)
fmt.Printf("}\n")
}
12 changes: 12 additions & 0 deletions src/go/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (
"os"
"sync"

"github.com/joho/godotenv"

"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
Expand Down Expand Up @@ -45,6 +47,11 @@ const (
)

func checkEnvVars(fatal bool) {
err := godotenv.Load()
if err != nil {
log.Fatalf("Error loading .env file")
}

taStoreContractAddr := os.Getenv("TA_STORE_CONTRACT_ADDRESS")
privKey := os.Getenv("PRIVATE_KEY")

Expand Down Expand Up @@ -108,6 +115,11 @@ func NewServer(rpcUrl string, privateKey string, taStoreContractAddr string) (*s
func StartServer(wg *sync.WaitGroup) {
defer wg.Done()

err := godotenv.Load()
if err != nil {
log.Fatalf("Error loading .env file")
}

// Ensure env variables are set
checkEnvVars(true)
// Setup framework and contract
Expand Down
5 changes: 4 additions & 1 deletion src/solidity/TransferableAccountStore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ contract TransferableAccountStore is Suapp, ITransferableAccountStore {
error OnlyOwnerCanUnlockAccount();
error OnlyApprovedAccount();
error OnlyUnlockAccount();
error InvalidTargetFunctionHash();

/**
* Functions
Expand Down Expand Up @@ -346,7 +347,9 @@ contract TransferableAccountStore is Suapp, ITransferableAccountStore {
view
returns (bool)
{
require(timedSignature.targetFunctionHash == targetFunctionHash, "Invalid targetFunctionHash");
if (timedSignature.targetFunctionHash != targetFunctionHash) {
revert InvalidTargetFunctionHash();
}
return SignatureVerifier.verifyTimedSignature(
timedSignature.validFor,
timedSignature.messageHash,
Expand Down

0 comments on commit 42e68cf

Please sign in to comment.