150 lines
2.8 KiB
Go
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
|
|
}
|