security/signature/signature.go
2024-09-30 19:02:10 -04:00

150 lines
2.8 KiB
Go

package signature
import (
"crypto/rand"
"encoding/base64"
"errors"
"github.com/cloudflare/circl/sign/bls"
)
type PrivateKey [32]byte
func (pk PrivateKey) Bls() (privKey *bls.PrivateKey[bls.KeyG2SigG1], err error) {
privKey = &bls.PrivateKey[bls.KeyG2SigG1]{}
err = privKey.UnmarshalBinary(pk[:])
if err != nil {
return
}
return
}
func (pk PrivateKey) Sign(msg []byte) (sig Signature, err error) {
privKey, err := pk.Bls()
if err != nil {
return
}
sig = Signature(bls.Sign(privKey, msg))
return
}
func (pk PrivateKey) SignKey(key PublicKey) (sig Signature, err error) {
pubKey := &bls.PublicKey[bls.KeyG2SigG1]{}
err = pubKey.UnmarshalBinary(key[:])
if err != nil {
return
}
return pk.Sign(key[:])
}
func (pk PrivateKey) String() (out string) {
out = base64.StdEncoding.EncodeToString(pk[:])
return
}
type PublicKey [96]byte
func (pk PublicKey) Bls() (pubKey *bls.PublicKey[bls.KeyG2SigG1], err error) {
pubKey = &bls.PublicKey[bls.KeyG2SigG1]{}
err = pubKey.UnmarshalBinary(pk[:])
if err != nil {
return
}
return
}
func (pk PublicKey) Verify(msg []byte, sig Signature) (ok bool, err error) {
pubKey, err := pk.Bls()
if err != nil {
return
}
ok = bls.Verify(pubKey, msg, sig[:])
return
}
func (pk PublicKey) String() (out string) {
out = base64.StdEncoding.EncodeToString(pk[:])
return
}
type Signature [48]byte
type Keypair struct {
PrivateKey
PublicKey
}
func NewKeypair() (kp *Keypair, err error) {
var (
ikm = make([]byte, 64)
salt = make([]byte, 32)
privKey *bls.PrivateKey[bls.KeyG2SigG1]
pubKey *bls.PublicKey[bls.KeyG2SigG1]
privKeyBytes = make([]byte, 32)
pubKeyBytes = make([]byte, 96)
)
_, err = rand.Read(ikm)
if err != nil {
return
}
_, err = rand.Read(salt)
if err != nil {
return
}
privKey, err = bls.KeyGen[bls.KeyG2SigG1](ikm, salt, []byte(""))
if err != nil {
return
}
privKeyBytes, err = privKey.MarshalBinary()
if err != nil {
return
}
pubKey = privKey.PublicKey()
pubKeyBytes, err = pubKey.MarshalBinary()
if err != nil {
return
}
kp = &Keypair{
PrivateKey: PrivateKey(privKeyBytes),
PublicKey: PublicKey(pubKeyBytes),
}
return
}
func (kp *Keypair) validate() (ok bool, err error) {
var testMessage [128]byte
_, err = rand.Read(testMessage[:])
if err != nil {
return
}
sig, _ := kp.PrivateKey.Sign(testMessage[:])
ok, _ = kp.PublicKey.Verify(testMessage[:], sig)
return
}
type SignatureService struct {
*Keypair
}
func NewSignatureService(signer *Keypair) (srv *SignatureService, err error) {
if signer == nil {
var ok bool
signer, err = NewKeypair()
if err != nil {
return
}
ok, err = signer.validate()
if err != nil {
return
}
if !ok {
err = errors.New("failed to validate new signer keypair")
return
}
}
srv = &SignatureService{
Keypair: signer,
}
return
}