func NewSecretKey(password *[]byte, N, r, p int) (*SecretKey, error) {
	const op errors.Op = "snacl.NewSecretKey"
	sk := SecretKey{
		Key: (*CryptoKey)(&[KeySize]byte{}),
	}
	sk.Parameters.N = N
	sk.Parameters.R = r
	sk.Parameters.P = p
	_, err := io.ReadFull(prng, sk.Parameters.Salt[:])
	if err != nil {
		return nil, errors.E(op, err)
	}
	err = sk.deriveKey(op, password)
	if err != nil {
		return nil, err
	}
	sk.Parameters.Digest = sha256.Sum256(sk.Key[:])
	return &sk, nil
}
NewSecretKey returns a SecretKey structure based on the passed parameters.
package snacl
import (
	"crypto/rand"
	"crypto/sha256"
	"crypto/subtle"
	"encoding/binary"
	"io"
	"runtime/debug"
	"decred.org/dcrwallet/v2/errors"
	"golang.org/x/crypto/nacl/secretbox"
	"golang.org/x/crypto/scrypt"
)
var (
	prng = rand.Reader
)
const (
	Overhead  = secretbox.Overhead
	KeySize   = 32
	NonceSize = 24
	DefaultN  = 16384  
	DefaultR  = 8
	DefaultP  = 1
)
type CryptoKey [KeySize]byte
func (ck *CryptoKey) Encrypt(in []byte) ([]byte, error) {
	const op errors.Op = "cryptokey.Encrypt"
	var nonce [NonceSize]byte
	_, err := io.ReadFull(prng, nonce[:])
	if err != nil {
		return nil, errors.E(op, err)
	}
	sealed := make([]byte, NonceSize, NonceSize+len(in)+Overhead)
	copy(sealed, nonce[:])
	sealed = secretbox.Seal(sealed, in, &nonce, (*[KeySize]byte)(ck))
	return sealed, nil
}
func (ck *CryptoKey) Decrypt(in []byte) ([]byte, error) {
	const op errors.Op = "cryptokey.Decrypt"
	if len(in) < NonceSize {
		return nil, errors.E(op, errors.Invalid, "missing nonce")
	}
	var nonce [NonceSize]byte
	copy(nonce[:], in[:NonceSize])
	blob := in[NonceSize:]
	opened, ok := secretbox.Open(nil, blob, &nonce, (*[KeySize]byte)(ck))
	if !ok {
		return nil, errors.E(op, errors.Crypto)
	}
	return opened, nil
}
func (ck *CryptoKey) Zero() {
	*ck = [KeySize]byte{}
}
func GenerateCryptoKey() (*CryptoKey, error) {
	const op errors.Op = "snacl.GenerateCryptoKey"
	var key CryptoKey
	_, err := io.ReadFull(prng, key[:])
	if err != nil {
		return nil, errors.E(op, err)
	}
	return &key, nil
}
type Parameters struct {
	Salt   [KeySize]byte
	Digest [sha256.Size]byte
	N      int
	R      int
	P      int
}
type SecretKey struct {
	Key        *CryptoKey
	Parameters Parameters
}
func zero(b []byte) {
	for i := range b {
		b[i] = 0
	}
}
func (sk *SecretKey) deriveKey(op errors.Op, password *[]byte) error {
	key, err := scrypt.Key(*password, sk.Parameters.Salt[:],
		sk.Parameters.N,
		sk.Parameters.R,
		sk.Parameters.P,
		len(sk.Key))
	if err != nil {
		return errors.E(op, err)
	}
	copy(sk.Key[:], key)
	zero(key)
	debug.FreeOSMemory()
	return nil
}
func (sk *SecretKey) Marshal() []byte {
	params := &sk.Parameters
	marshalled := make([]byte, KeySize+sha256.Size+24)
	b := marshalled
	copy(b[:KeySize], params.Salt[:])
	b = b[KeySize:]
	copy(b[:sha256.Size], params.Digest[:])
	b = b[sha256.Size:]
	binary.LittleEndian.PutUint64(b[:8], uint64(params.N))
	b = b[8:]
	binary.LittleEndian.PutUint64(b[:8], uint64(params.R))
	b = b[8:]
	binary.LittleEndian.PutUint64(b[:8], uint64(params.P))
	return marshalled
}
func (sk *SecretKey) Unmarshal(marshalled []byte) error {
	const op errors.Op = "secretkey.Unmarshal"
	if sk.Key == nil {
		sk.Key = (*CryptoKey)(&[KeySize]byte{})
	}
	if len(marshalled) != KeySize+sha256.Size+24 {
		return errors.E(op, errors.Encoding, errors.Errorf("bad marshalled data len %d", len(marshalled)))
	}
	params := &sk.Parameters
	copy(params.Salt[:], marshalled[:KeySize])
	marshalled = marshalled[KeySize:]
	copy(params.Digest[:], marshalled[:sha256.Size])
	marshalled = marshalled[sha256.Size:]
	params.N = int(binary.LittleEndian.Uint64(marshalled[:8]))
	marshalled = marshalled[8:]
	params.R = int(binary.LittleEndian.Uint64(marshalled[:8]))
	marshalled = marshalled[8:]
	params.P = int(binary.LittleEndian.Uint64(marshalled[:8]))
	return nil
}
func (sk *SecretKey) Zero() {
	sk.Key.Zero()
}
func (sk *SecretKey) DeriveKey(password *[]byte) error {
	const op errors.Op = "secretkey.DeriveKey"
	if err := sk.deriveKey(op, password); err != nil {
		return err
	}
	digest := sha256.Sum256(sk.Key[:])
	if subtle.ConstantTimeCompare(digest[:], sk.Parameters.Digest[:]) != 1 {
		return errors.E(op, errors.Passphrase)
	}
	return nil
}
func (sk *SecretKey) Encrypt(in []byte) ([]byte, error) {
	const op errors.Op = "secretkey.Encrypt"
	out, err := sk.Key.Encrypt(in)
	if err != nil {
		return nil, errors.E(op, err)
	}
	return out, nil
}
func (sk *SecretKey) Decrypt(in []byte) ([]byte, error) {
	const op errors.Op = "secretkey.Decrypt"
	out, err := sk.Key.Decrypt(in)
	if err != nil {
		return nil, errors.E(op, err)
	}
	return out, nil
}