sig/sig.go
121 lines
1// Package sig verifies Ed25519 signatures under the protocol's strictness2// rules: s < L, and R and public keys canonically encoded (RFC 8032).3//4// The standard library rejects s ≥ L but, like most implementations,5// accepts non-canonical point encodings (a y-coordinate ≥ p, or x = 0 with6// the sign bit set). Those are rejected here before verification, so that7// every node accepts exactly the same signatures.8package sig910import (11"crypto/ed25519"12"crypto/rand"13"math/big"14)1516// PublicKey is a 32-byte Ed25519 public key; it is also the trie key of17// address-keyed tries.18type PublicKey [32]byte1920// Signature is a 64-byte Ed25519 signature, R ‖ s.21type Signature [64]byte2223var (24// p = 2^255 − 19, the field prime.25fieldP = func() *big.Int {26p := new(big.Int).Lsh(big.NewInt(1), 255)27return p.Sub(p, big.NewInt(19))28}()29// pMinus1 = p − 1 (the y-coordinate of the other point with x = 0).30pMinus1 = new(big.Int).Sub(fieldP, big.NewInt(1))31// L = 2^252 + 27742317777372353535851937790883648493, the group order.32groupL = func() *big.Int {33l, _ := new(big.Int).SetString("7237005577332262213973186563042994240857116359379907606001950938285454250989", 10)34return l35}()36)3738// leToInt interprets 32 little-endian bytes as an integer.39func leToInt(b [32]byte) *big.Int {40var be [32]byte41for i := range b {42be[31-i] = b[i]43}44return new(big.Int).SetBytes(be[:])45}4647// PointCanonical reports whether enc is a canonical point encoding: the48// y-coordinate is reduced (y < p), and the sign bit is clear when x = 049// (y = 1 or y = p − 1). It does not check that the point is on the curve;50// verification does.51func PointCanonical(enc [32]byte) bool {52sign := enc[31]&0x80 != 053enc[31] &= 0x7f54y := leToInt(enc)55if y.Cmp(fieldP) >= 0 {56return false57}58if sign && (y.Cmp(big.NewInt(1)) == 0 || y.Cmp(pMinus1) == 0) {59return false60}61return true62}6364// ScalarCanonical reports whether s < L.65func ScalarCanonical(s [32]byte) bool {66return leToInt(s).Cmp(groupL) < 067}6869// Valid reports whether sig is well-formed under the strictness rules,70// without checking it against a message: R canonical, s < L.71func (sig *Signature) Valid() bool {72var r, s [32]byte73copy(r[:], sig[:32])74copy(s[:], sig[32:])75return PointCanonical(r) && ScalarCanonical(s)76}7778// Verify reports whether sig is a valid, canonical signature by pub over79// msg. A non-canonical signature or public key never verifies.80func Verify(pub PublicKey, msg []byte, sig Signature) bool {81if !PointCanonical(pub) || !sig.Valid() {82return false83}84return ed25519.Verify(ed25519.PublicKey(pub[:]), msg, sig[:])85}8687// Keypair holds a signing key, for wallets and tests.88type Keypair struct {89Public PublicKey90private ed25519.PrivateKey91}9293// Generate creates a fresh random keypair.94func Generate() (*Keypair, error) {95pub, priv, err := ed25519.GenerateKey(rand.Reader)96if err != nil {97return nil, err98}99var kp Keypair100copy(kp.Public[:], pub)101kp.private = priv102return &kp, nil103}104105// FromSeed derives a keypair from a 32-byte seed (RFC 8032 private key).106func FromSeed(seed [32]byte) *Keypair {107priv := ed25519.NewKeyFromSeed(seed[:])108var kp Keypair109copy(kp.Public[:], priv.Public().(ed25519.PublicKey))110kp.private = priv111return &kp112}113114// Sign signs msg. Signatures produced by the standard library are always115// canonical.116func (k *Keypair) Sign(msg []byte) Signature {117var s Signature118copy(s[:], ed25519.Sign(k.private, msg))119return s120}