1

I am trying to build a blockchain project when I'm catching an issue about gob Serialize. I have a struct Wallet which uses elliptic.P256() Curve struct, and when I'm trying to serialize Wallet, a bug of no exported fields occured.

Really hope for some help.

There is my code.

const walletFile = "Wallets.dat"

type Wallets struct {
    WalletsMap map[string]*Wallet
}

type Wallet struct {
    PrivateKey ecdsa.PrivateKey
    PublicKey []byte
}

func (w *Wallets) SaveWallets() {
    var content bytes.Buffer

    gob.Register(elliptic.P256())

    encoder := gob.NewEncoder(&content)
    err := encoder.Encode(&w)
    if err != nil {
        log.Panic(err)
    }

    err = ioutil.WriteFile(walletFile, content.Bytes(), 0644)
    if err != nil {
        log.Panic(err)
    }

}


func NewWallets() (*Wallets, error) {
    if _, err := os.Stat(walletFile); os.IsNotExist(err) {
        wallets := &Wallets{}
        wallets.WalletsMap = make(map[string]*Wallet)
        return wallets, err
    }

    fileContent, err := ioutil.ReadFile(walletFile)
    if err != nil {
        log.Panic(err)
    }

    var wallets Wallets
    gob.Register(elliptic.P256())
    decoder := gob.NewDecoder(bytes.NewReader(fileContent))
    err = decoder.Decode(&wallets)
    if err != nil {
        log.Panic(err)
    }

    return &wallets, nil
}

The issue

2022/09/18 19:42:33 gob: type elliptic.p256Curve has no exported fields
panic: gob: type elliptic.p256Curve has no exported fields

Vango Lu
  • 21
  • 1
  • You can either export the fields of `elliptic.p256Curve` or write custom function to Encode/Decode `elliptic.p256Curve` – twiny Sep 18 '22 at 12:57
  • 1
    Thanks! I'm actually trying to find an easier way, but it's difficult. I'll try to export the fields then. – Vango Lu Sep 19 '22 at 07:22

4 Answers4

1

Change your Go version to 1.18.10 for less. I have encountered the same issue due to the latest Go version i.e. 1.19.5

We need to downgrade the Go version the old way because Go doesn't provide anything like a fancy version manager.

Steps to downgrade Go Version:

  1. Uninstall the existing Go version

    To uninstall go, locate where Go is on your system.

    $where go This command will locate the program file in the user path.

    To uninstall, delete the /usr/local/go directory or the source directory which you have received as output in the previous command. Use command $ sudo rm -rf /usr/local/go to delete the Go directory.

    To confirm run the command $ go version, system will prompt "command go not found" if you have successfully deleted Go ditrectory.

  2. Install the new version

    Go to the downloads page and download the version release(choose installer instead of Archive to make things easy for yourself) which is compatible with your OS and Architecture. Unzip and extract the package installer and the new Go version is now installed in your system.

After that, you will need to restart your terminal for the change to take effect. To check if you have installed Go successfully, run the command $go version. The command prints the installed version of Go. Also make sure that GOROOT and GOPATH haven't changed.

Proton
  • 343
  • 4
  • 18
1

I have a solution here

In go1.20, the serialization of god requires reflection, while there is an interface in the attribute of type ecdsa.PrivateKey, which may not be usable.

How to solve it? Ecdsa.PrivateKey maybe have a specialized serialization method.

The demo is as follows:

type Wallet struct {
    PrivateKey ecdsa.PrivateKey
    PublicKey  []byte
}

func (w *Wallet) Save() {
    filename := filepath.Join(constcoe.Wallets, string(w.Address())+".wlt")

    privKeyBytes, err := x509.MarshalECPrivateKey(&w.PrivateKey)
    utils.Handle(err)
    privKeyFile, err := os.Create(filename)
    utils.Handle(err)
    err = pem.Encode(privKeyFile, &pem.Block{
        // Type:  "EC PRIVATE KEY",
        Bytes: privKeyBytes,
    })
    utils.Handle(err)
    privKeyFile.Close()
}


func LoadWallet(address string) *Wallet {
    filename := filepath.Join(constcoe.Wallets, address+".wlt")
    if !utils.FileExists(filename) {
        utils.Handle(errors.New("no wallet with such address"))
    }

    privKeyFile, err := os.ReadFile(filename)
    utils.Handle(err)
    pemBlock, _ := pem.Decode(privKeyFile)
    utils.Handle(err)
    privKey, err := x509.ParseECPrivateKey(pemBlock.Bytes)
    utils.Handle(err)
    publicKey := append(privKey.PublicKey.X.Bytes(), privKey.PublicKey.Y.Bytes()...)
    return &Wallet{
        PrivateKey: *privKey,
        PublicKey:  publicKey,
    }
}
zweix
  • 11
  • 1
0

What you seem to be trying to do here is serialize a P256 curve from the crypto/elliptic package. The issue is that the P256() function returns an interface called elliptic.Curve.

What this error is telling you is that the underlying type of the elliptic.Curve, in this case elliptic.p256Curve, doesn't have any fields that are exported (named with the first letter capitalized). Go's reflect package, which encoding/gob uses, only works on exported fields.

You might want to try using crypto/elliptic's Marshal() or GenerateKey() functions.

Arsen6331
  • 1
  • 1
  • 4
  • Thanks! You explained this really clearly that I totally understood my problem! I'm actually trying to serialize a curve, but some no exported fields in crypto/elliptic package really stopped me. I can only solve the problem by changing all the fields into exported or I may try not to serialize any curve. – Vango Lu Sep 22 '22 at 07:36
  • Unfortunately, since you don't have control of the `crypto/elliptic` package, you can't make the fields exported, since in order to do so, you'd have to change their names so they start with a capital letter. Based on the function signatures in the `elliptic` package, I believe you're not supposed to serialize the entire curve, but rather a point on the curve or a generated key. – Arsen6331 Sep 22 '22 at 17:30
  • Well, I finally give up serialize the entire curve to solve my problem~ – Vango Lu Sep 23 '22 at 11:52
-1

Its problem in 1.9.* versions of Go. Just install 1.8.7 for example. Everything gonna work fine after this)