github.com/code-to-go/safepool.lib@v0.0.0-20221205180519-ee25e63c226e/security/signature.go (about) 1 package security 2 3 import ( 4 "bytes" 5 "crypto/ed25519" 6 "encoding/base64" 7 8 "github.com/code-to-go/safepool.lib/core" 9 ) 10 11 type PublicKey ed25519.PublicKey 12 type PrivateKey ed25519.PrivateKey 13 14 const ( 15 PublicKeySize = ed25519.PublicKeySize 16 PrivateKeySize = ed25519.PrivateKeySize 17 SignatureSize = ed25519.SignatureSize 18 ) 19 20 type SignedData struct { 21 Signature [SignatureSize]byte 22 Signer PublicKey 23 } 24 25 type Public struct { 26 Id PublicKey 27 Nick string 28 Email string 29 } 30 31 func Sign(identity Identity, data []byte) ([]byte, error) { 32 private := identity.SignatureKey.Private 33 return ed25519.Sign(ed25519.PrivateKey(private), data), nil 34 } 35 36 func Verify(id string, data []byte, sig []byte) bool { 37 public, err := base64.StdEncoding.DecodeString(id) 38 if core.IsErr(err, "invalid id '%s': %v", id) { 39 return false 40 } 41 42 for off := 0; off < len(sig); off += SignatureSize { 43 if func() bool { 44 defer func() { recover() }() 45 return ed25519.Verify(ed25519.PublicKey(public), data, sig[off:off+SignatureSize]) 46 }() { 47 return true 48 } 49 } 50 return false 51 } 52 53 type SignedHashEvidence struct { 54 Key []byte `json:"k"` 55 Signature []byte `json:"s"` 56 } 57 58 type SignedHash struct { 59 Hash []byte `json:"h"` 60 Evidences []SignedHashEvidence `json:"e"` 61 } 62 63 func NewSignedHash(hash []byte, i Identity) (SignedHash, error) { 64 signature, err := Sign(i, hash) 65 if core.IsErr(err, "cannot sign with identity %s: %v", base64.StdEncoding.EncodeToString(i.SignatureKey.Public)) { 66 return SignedHash{}, err 67 } 68 69 return SignedHash{ 70 Hash: hash, 71 Evidences: []SignedHashEvidence{ 72 { 73 Key: i.SignatureKey.Public, 74 Signature: signature, 75 }, 76 }, 77 }, nil 78 } 79 80 func AppendToSignedHash(s SignedHash, i Identity) error { 81 signature, err := Sign(i, s.Hash) 82 if core.IsErr(err, "cannot sign with identity %s: %v", base64.StdEncoding.EncodeToString(i.SignatureKey.Public)) { 83 return err 84 } 85 s.Evidences = append(s.Evidences, SignedHashEvidence{ 86 Key: i.SignatureKey.Public, 87 Signature: signature, 88 }) 89 return nil 90 } 91 92 func VerifySignedHash(s SignedHash, trusts []Identity, hash []byte) bool { 93 if !bytes.Equal(s.Hash, hash) { 94 return false 95 } 96 97 for _, e := range s.Evidences { 98 for _, t := range trusts { 99 if bytes.Equal(e.Key, t.SignatureKey.Public) { 100 if Verify(t.Id(), hash, e.Signature) { 101 return true 102 } 103 } 104 } 105 } 106 return false 107 }