github.com/storacha/go-ucanto@v0.7.2/principal/ed25519/signer/signer.go (about)

     1  package signer
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/ed25519"
     6  	"crypto/rand"
     7  	"fmt"
     8  
     9  	"github.com/multiformats/go-multibase"
    10  	"github.com/multiformats/go-varint"
    11  	"github.com/storacha/go-ucanto/did"
    12  	"github.com/storacha/go-ucanto/principal"
    13  	"github.com/storacha/go-ucanto/principal/ed25519/verifier"
    14  	"github.com/storacha/go-ucanto/ucan/crypto/signature"
    15  )
    16  
    17  const Code = 0x1300
    18  const Name = verifier.Name
    19  
    20  const SignatureCode = verifier.SignatureCode
    21  const SignatureAlgorithm = verifier.SignatureAlgorithm
    22  
    23  var privateTagSize = varint.UvarintSize(Code)
    24  var publicTagSize = varint.UvarintSize(verifier.Code)
    25  
    26  const keySize = 32
    27  
    28  var size = privateTagSize + keySize + publicTagSize + keySize
    29  var pubKeyOffset = privateTagSize + keySize
    30  
    31  func Generate() (principal.Signer, error) {
    32  	pub, priv, err := ed25519.GenerateKey(rand.Reader)
    33  	if err != nil {
    34  		return nil, fmt.Errorf("generating Ed25519 key: %w", err)
    35  	}
    36  	s := make(Ed25519Signer, size)
    37  	varint.PutUvarint(s, Code)
    38  	copy(s[privateTagSize:], priv)
    39  	varint.PutUvarint(s[pubKeyOffset:], verifier.Code)
    40  	copy(s[pubKeyOffset+publicTagSize:], pub)
    41  	return s, nil
    42  }
    43  
    44  func Parse(str string) (principal.Signer, error) {
    45  	_, bytes, err := multibase.Decode(str)
    46  	if err != nil {
    47  		return nil, fmt.Errorf("decoding multibase string: %w", err)
    48  	}
    49  	return Decode(bytes)
    50  }
    51  
    52  func Format(signer principal.Signer) (string, error) {
    53  	return multibase.Encode(multibase.Base64pad, signer.Encode())
    54  }
    55  
    56  func Decode(b []byte) (principal.Signer, error) {
    57  	if len(b) != size {
    58  		return nil, fmt.Errorf("invalid length: %d wanted: %d", len(b), size)
    59  	}
    60  
    61  	prc, err := varint.ReadUvarint(bytes.NewReader(b))
    62  	if err != nil {
    63  		return nil, fmt.Errorf("reading private key codec: %w", err)
    64  	}
    65  	if prc != Code {
    66  		return nil, fmt.Errorf("invalid private key codec: %d", prc)
    67  	}
    68  
    69  	puc, err := varint.ReadUvarint(bytes.NewReader(b[pubKeyOffset:]))
    70  	if err != nil {
    71  		return nil, fmt.Errorf("reading public key codec: %w", err)
    72  	}
    73  	if puc != verifier.Code {
    74  		return nil, fmt.Errorf("invalid public key codec: %d", puc)
    75  	}
    76  
    77  	_, err = verifier.Decode(b[pubKeyOffset:])
    78  	if err != nil {
    79  		return nil, fmt.Errorf("decoding public key: %w", err)
    80  	}
    81  
    82  	s := make(Ed25519Signer, size)
    83  	copy(s, b)
    84  
    85  	return s, nil
    86  }
    87  
    88  // FromRaw takes raw ed25519 private key bytes and tags with the ed25519 signer
    89  // and verifier multiformat codes, returning an ed25519 signer.
    90  func FromRaw(b []byte) (principal.Signer, error) {
    91  	if len(b) != ed25519.PrivateKeySize {
    92  		return nil, fmt.Errorf("invalid length: %d wanted: %d", len(b), ed25519.PrivateKeySize)
    93  	}
    94  	s := make(Ed25519Signer, size)
    95  	varint.PutUvarint(s, Code)
    96  	copy(s[privateTagSize:privateTagSize+keySize], b[:ed25519.PrivateKeySize-ed25519.PublicKeySize])
    97  	varint.PutUvarint(s[pubKeyOffset:], verifier.Code)
    98  	copy(s[pubKeyOffset+publicTagSize:], b[ed25519.PrivateKeySize-ed25519.PublicKeySize:ed25519.PrivateKeySize])
    99  	return s, nil
   100  }
   101  
   102  type Ed25519Signer []byte
   103  
   104  func (s Ed25519Signer) Code() uint64 {
   105  	return Code
   106  }
   107  
   108  func (s Ed25519Signer) SignatureCode() uint64 {
   109  	return SignatureCode
   110  }
   111  
   112  func (s Ed25519Signer) SignatureAlgorithm() string {
   113  	return SignatureAlgorithm
   114  }
   115  
   116  func (s Ed25519Signer) Verifier() principal.Verifier {
   117  	return verifier.Ed25519Verifier(s[pubKeyOffset:])
   118  }
   119  
   120  func (s Ed25519Signer) DID() did.DID {
   121  	id, _ := did.Decode(s[pubKeyOffset:])
   122  	return id
   123  }
   124  
   125  func (s Ed25519Signer) Encode() []byte {
   126  	return s
   127  }
   128  
   129  func (s Ed25519Signer) Raw() []byte {
   130  	pk := make(ed25519.PrivateKey, ed25519.PrivateKeySize)
   131  	copy(pk[0:ed25519.PublicKeySize], s[privateTagSize:pubKeyOffset])
   132  	copy(pk[ed25519.PrivateKeySize-ed25519.PublicKeySize:ed25519.PrivateKeySize], s[pubKeyOffset+publicTagSize:pubKeyOffset+publicTagSize+keySize])
   133  	return pk
   134  }
   135  
   136  func (s Ed25519Signer) Sign(msg []byte) signature.SignatureView {
   137  	return signature.NewSignatureView(signature.NewSignature(signature.EdDSA, ed25519.Sign(s.Raw(), msg)))
   138  }