go-lib-crypto
is a unified crypto library for Waves Platform. It has a unified set of functions corresponding with unified-declarations
.
This library meant to be used in client applications. That's why its API is relatively simple.
The following could be done using the library:
- Calculation of a hash digest of various hash functions used by Waves
- Encoding and decoding of byte slices in BASE58 and BASE64 string representation
- Key pair generation from seed phrase
- Waves address generation and verification
- Random seed phrase generation and verification
- Signing of bytes message
- Verification of signed message
go get -u github.com/wavesplatform/go-lib-crypto
import "github.com/wavesplatform/go-lib-crypto"
For the purpose of unification the API of the library made in form of the interface. To instantiate the un-exported structure that implements the interface call the NewWavesCrypto
function.
crypto := wavesplatform.NewWavesCrypto()
The three hash functions used by Waves are supported:
- SHA-256
- BLAKE2b-256
- Keccak-256 (legacy version)
Every hash functions accepts one parameter of type Bytes
. The Bytes
type wraps a slice of bytes.
package main import ( "encoding/hex" "fmt" "github.com/wavesplatform/go-lib-crypto" ) func main() { bytes, _ := hex.DecodeString("fd08be957bda07dc529ad8100df732f9ce12ae3e42bcda6acabe12c02dfd6989") c := wavesplatform.NewWavesCrypto() blake := c.Blake2b(bytes) keccak := c.Keccak(bytes) sha := c.Sha256(bytes) fmt.Println("BLAKE2b-256:", hex.EncodeToString(blake)) fmt.Println("Keccak-256:", hex.EncodeToString(keccak)) fmt.Println("SHA-256:", hex.EncodeToString(sha)) }
The output should be like this:
BLAKE2b-256: c425f69e3be14c929d18b2808831cbaeb2733c9e6b9c5ed37c3601086f202396 Keccak-256: 14a0d0ee74865d8d721c4218768b7c39fd365b53f0359d6d28d82dc97450f583 SHA-256: 7ed1b5b6867c0d6c98097676adc00b6049882e473441ac5ff3613df48b69f9f3
See the example on play.golang.org.
One can create a new key pair from the seed phrase. Library defines types for Seed
, PrivateKey
, PublicKey
(wrappers over string
) and structure for KeyPair
that combines the private and public keys.
The function RandomSeed
creates a new random seed phrase of 15 words. The seed generation follows the BIP39 standard.
The keys generation functions KeyPair
, PublicKey
and PrivateKey
accept the seed phrase as its parameters and produces a KeyPair
, PublicKey
or PrivateKey
relatively. In latter two cases the whole key pair is produced, but only a part of it returned to the user.
Here is the example.
package main import ( "fmt" "github.com/wavesplatform/go-lib-crypto" ) func main() { c := wavesplatform.NewWavesCrypto() seed := c.RandomSeed() fmt.Println("SEED:", seed) pair := c.KeyPair(seed) fmt.Println("PAIR:", "PRIVATE KEY:", pair.PrivateKey, "PUBLIC KEY:", pair.PublicKey) sk := c.PrivateKey(seed) fmt.Println("PRIVATE KEY:", sk) pk := c.PublicKey(seed) fmt.Println("PUBLIC KEY:", pk) }
There is an Address
type which wraps the string. An address could be created from PublicKey
or Seed
using functions Address
or AddressFromSeed
. In both cases the WavesChainID
byte should be provided as second parameter. It is possible to verify the correctness of an Address string using functions VerifyAddressChecksum
or VerifyAddress
. The first function checks that the address has correct length and version and the built-in checksum is correct. The second one additionally checks that the address contains the correct WavesChainID
.
package main import ( "fmt" "github.com/wavesplatform/go-lib-crypto" ) func main() { c := wavesplatform.NewWavesCrypto() seed := c.RandomSeed() fmt.Println("SEED:", seed) pair := c.KeyPair(seed) fmt.Println("PAIR:", "PRIVATE KEY:", pair.PrivateKey, "PUBLIC KEY:", pair.PublicKey) address := c.Address(pair.PublicKey, wavesplatform.TestNet) fmt.Println("ADDRESS 1:", address) address2 := c.AddressFromSeed(seed, wavesplatform.TestNet) fmt.Println("ADDRESS 2:", address2) fmt.Println("CHECKSUM OK:", c.VerifyAddressChecksum(address)) fmt.Println("ADDRESS ON TESTNET OK:", c.VerifyAddress(address, wavesplatform.TestNet)) fmt.Println("ADDRESS ON MAINNET OK:", c.VerifyAddress(address, wavesplatform.MainNet)) }
Try the example.
The library offers two functions to sign bytes (SignBytes
and SignBytesBySeed
) and one to verify a signature (VerifySignature
).
Here is the example of using those functions.
package main import ( "fmt" "encoding/hex" "github.com/wavesplatform/go-lib-crypto" ) func main() { bytes, _ := hex.DecodeString("fd08be957bda07dc529ad8100df732f9ce12ae3e42bcda6acabe12c02dfd6989") other, _ := hex.DecodeString("54686520696e636f7272656374206d657373616765") c := wavesplatform.NewWavesCrypto() seed := c.RandomSeed() fmt.Println("SEED:", seed) pair := c.KeyPair(seed) fmt.Println("PAIR:", "PRIVATE KEY:", pair.PrivateKey, "PUBLIC KEY:", pair.PublicKey) sig1 := c.SignBytes(bytes, pair.PrivateKey) fmt.Println("SIGNATURE 1:", hex.EncodeToString(sig1)) sig2 := c.SignBytesBySeed(bytes, seed) fmt.Println("SIGNATURE 2:", hex.EncodeToString(sig2)) fmt.Println("SIGNATURE 1 OK:", c.VerifySignature(pair.PublicKey, bytes, sig1)) fmt.Println("SIGNATURE 2 OK:", c.VerifySignature(pair.PublicKey, bytes, sig2)) fmt.Println("SIGNATURE 1 ON OTHER OK:", c.VerifySignature(pair.PublicKey, other, sig1)) fmt.Println("SIGNATURE 2 ON OTHER OK:", c.VerifySignature(pair.PublicKey, other, sig2)) }