// Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package key

import "encoding/json"

// ControlPrivate is a Tailscale control plane private key.
//
// It is functionally equivalent to a MachinePrivate, but serializes
// to JSON as a byte array rather than a typed string, because our
// control plane database stores the key that way.
//
// Deprecated: this type should only be used in Tailscale's control
// plane, where existing database serializations require this
// less-good serialization format to persist. Other control plane
// implementations can use MachinePrivate with no downsides.
type ControlPrivate struct {
	mkey MachinePrivate // unexported so we can limit the API surface to only exactly what we need
}

// NewControl generates and returns a new control plane private key.
func NewControl() ControlPrivate {
	return ControlPrivate{NewMachine()}
}

// IsZero reports whether k is the zero value.
func (k ControlPrivate) IsZero() bool {
	return k.mkey.IsZero()
}

// Public returns the MachinePublic for k.
// Panics if ControlPrivate is zero.
func (k ControlPrivate) Public() MachinePublic {
	return k.mkey.Public()
}

// MarshalJSON implements json.Marshaler.
func (k ControlPrivate) MarshalJSON() ([]byte, error) {
	return json.Marshal(k.mkey.k)
}

// UnmarshalJSON implements json.Unmarshaler.
func (k *ControlPrivate) UnmarshalJSON(bs []byte) error {
	return json.Unmarshal(bs, &k.mkey.k)
}

// SealTo wraps cleartext into a NaCl box (see
// golang.org/x/crypto/nacl) to p, authenticated from k, using a
// random nonce.
//
// The returned ciphertext is a 24-byte nonce concatenated with the
// box value.
func (k ControlPrivate) SealTo(p MachinePublic, cleartext []byte) (ciphertext []byte) {
	return k.mkey.SealTo(p, cleartext)
}

// SharedKey returns the precomputed Nacl box shared key between k and p.
func (k ControlPrivate) SharedKey(p MachinePublic) MachinePrecomputedSharedKey {
	return k.mkey.SharedKey(p)
}

// OpenFrom opens the NaCl box ciphertext, which must be a value
// created by SealTo, and returns the inner cleartext if ciphertext is
// a valid box from p to k.
func (k ControlPrivate) OpenFrom(p MachinePublic, ciphertext []byte) (cleartext []byte, ok bool) {
	return k.mkey.OpenFrom(p, ciphertext)
}
