1

I am using tzgo. I am trying to verify the block signature and i could not figure out a way to extract the public key from the signatures. The rpc RCP gave a 403 response which provides the public key (not hash) which can be then used to verify the signatures. Is there another way in which i can do this?

2 Answers 2

1

I could not retrieve the public key from the signature itself but found out that we can get the exposed public key using the method GetManagerKey() in rpc client.

exposedPk, err := c.GetManagerKey(ctx, address, rpc.BlockLevel(blockLevel))

This method helps you to get the exposed public key of the address in a particular block level.

Now using the public key we can validate any signatures as long as you have the data that was signed by the private key of the address. We can do that using the Verify() method.

err = exposedPk.Verify(data<[]byte>, signature<tezos.Signature>)
1

Error 403 usually means the RPC node has restricted access to the node's context endpoints. Use a node with open RPC endpoints like https://rpc.tzstats.com.

Here's an example that works with the recent TzGo version v1.16.3:

package main

import (
    "context"
    "fmt"

    "blockwatch.cc/tzgo/codec"
    "blockwatch.cc/tzgo/rpc"
)

func main() {
    if err := run(); err != nil {
        fmt.Errorf("Error:", err)
    }
}

func run() error {
    ctx, cancel := context.WithCancel(context.Background())
    defer cancel()

    c, err := rpc.NewClient("https://rpc.tzstats.com", nil)
    if err != nil {
        return err
    }

    // pick a block
    id := rpc.BlockAlias("head")
    b, err := c.GetBlock(ctx, id)
    if err != nil {
        return err
    }

    // fetch proposer pubkey
    pk, err := c.GetManagerKey(ctx, b.Metadata.Proposer, id)
    if err != nil {
        return err
    }

    // build header (codec package uses a custom type!)
    bh := codec.BlockHeader{
        Level:            int32(b.Header.Level),
        Proto:            byte(b.Header.Proto),
        Predecessor:      b.Header.Predecessor,
        Timestamp:        b.Header.Timestamp,
        ValidationPass:   byte(b.Header.ValidationPass),
        OperationsHash:   b.Header.OperationsHash,
        Fitness:          b.Header.Fitness,
        Context:          b.Header.Context,
        PayloadHash:      b.Header.PayloadHash,
        PayloadRound:     b.Header.PayloadRound,
        ProofOfWorkNonce: b.Header.ProofOfWorkNonce,
        LbToggleVote:     b.Header.LiquidityBakingToggleVote,
        ChainId:          &b.ChainId,
    }
    if b.Header.SeedNonceHash != nil {
        bh.SeedNonceHash = *b.Header.SeedNonceHash
    }

    // create the pre-image
    digest := bh.Digest()

    // verify the sig
    if err := pk.Verify(digest, b.Header.Signature); err != nil {
        return err
    }
    fmt.Println("OK")
    return nil
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.