github.com/cloudflare/circl@v1.5.0/sign/eddilithium3/eddilithium.go (about) 1 // Package eddilithium3 implements the hybrid signature scheme Ed448-Dilithium3. 2 package eddilithium3 3 4 import ( 5 "crypto" 6 cryptoRand "crypto/rand" 7 "errors" 8 "io" 9 10 "github.com/cloudflare/circl/internal/sha3" 11 "github.com/cloudflare/circl/sign" 12 "github.com/cloudflare/circl/sign/dilithium/mode3" 13 "github.com/cloudflare/circl/sign/ed448" 14 ) 15 16 const ( 17 // SeedSize is the length of the seed for NewKeyFromSeed 18 SeedSize = ed448.SeedSize // > mode3.SeedSize 19 20 // PublicKeySize is the length in bytes of the packed public key. 21 PublicKeySize = mode3.PublicKeySize + ed448.PublicKeySize 22 23 // PrivateKeySize is the length in bytes of the packed public key. 24 PrivateKeySize = mode3.PrivateKeySize + ed448.SeedSize 25 26 // SignatureSize is the length in bytes of the signatures. 27 SignatureSize = mode3.SignatureSize + ed448.SignatureSize 28 ) 29 30 // PublicKey is the type of an EdDilithium3 public key. 31 type PublicKey struct { 32 e ed448.PublicKey 33 d mode3.PublicKey 34 } 35 36 // PrivateKey is the type of an EdDilithium3 private key. 37 type PrivateKey struct { 38 e ed448.PrivateKey 39 d mode3.PrivateKey 40 } 41 42 // GenerateKey generates a public/private key pair using entropy from rand. 43 // If rand is nil, crypto/rand.Reader will be used. 44 func GenerateKey(rand io.Reader) (*PublicKey, *PrivateKey, error) { 45 var seed [SeedSize]byte 46 if rand == nil { 47 rand = cryptoRand.Reader 48 } 49 _, err := io.ReadFull(rand, seed[:]) 50 if err != nil { 51 return nil, nil, err 52 } 53 54 pk, sk := NewKeyFromSeed(&seed) 55 return pk, sk, nil 56 } 57 58 // NewKeyFromSeed derives a public/private key pair using the given seed. 59 func NewKeyFromSeed(seed *[SeedSize]byte) (*PublicKey, *PrivateKey) { 60 var seed1 [32]byte 61 var seed2 [ed448.SeedSize]byte 62 63 h := sha3.NewShake256() 64 _, _ = h.Write(seed[:]) 65 _, _ = h.Read(seed1[:]) 66 _, _ = h.Read(seed2[:]) 67 dpk, dsk := mode3.NewKeyFromSeed(&seed1) 68 esk := ed448.NewKeyFromSeed(seed2[:]) 69 70 return &PublicKey{esk.Public().(ed448.PublicKey), *dpk}, &PrivateKey{esk, *dsk} 71 } 72 73 // SignTo signs the given message and writes the signature into signature. 74 // It will panic if signature is not of length at least SignatureSize. 75 func SignTo(sk *PrivateKey, msg []byte, signature []byte) { 76 mode3.SignTo( 77 &sk.d, 78 msg, 79 signature[:mode3.SignatureSize], 80 ) 81 esig := ed448.Sign( 82 sk.e, 83 msg, 84 "", 85 ) 86 copy(signature[mode3.SignatureSize:], esig[:]) 87 } 88 89 // Verify checks whether the given signature by pk on msg is valid. 90 func Verify(pk *PublicKey, msg []byte, signature []byte) bool { 91 if !mode3.Verify( 92 &pk.d, 93 msg, 94 signature[:mode3.SignatureSize], 95 ) { 96 return false 97 } 98 if !ed448.Verify( 99 pk.e, 100 msg, 101 signature[mode3.SignatureSize:], 102 "", 103 ) { 104 return false 105 } 106 return true 107 } 108 109 // Unpack unpacks pk to the public key encoded in buf. 110 func (pk *PublicKey) Unpack(buf *[PublicKeySize]byte) { 111 var tmp [mode3.PublicKeySize]byte 112 copy(tmp[:], buf[:mode3.PublicKeySize]) 113 pk.d.Unpack(&tmp) 114 pk.e = make([]byte, ed448.PublicKeySize) 115 copy(pk.e, buf[mode3.PublicKeySize:]) 116 } 117 118 // Unpack sets sk to the private key encoded in buf. 119 func (sk *PrivateKey) Unpack(buf *[PrivateKeySize]byte) { 120 var tmp [mode3.PrivateKeySize]byte 121 copy(tmp[:], buf[:mode3.PrivateKeySize]) 122 sk.d.Unpack(&tmp) 123 sk.e = ed448.NewKeyFromSeed(buf[mode3.PrivateKeySize:]) 124 } 125 126 // Pack packs the public key into buf. 127 func (pk *PublicKey) Pack(buf *[PublicKeySize]byte) { 128 var tmp [mode3.PublicKeySize]byte 129 pk.d.Pack(&tmp) 130 copy(buf[:mode3.PublicKeySize], tmp[:]) 131 copy(buf[mode3.PublicKeySize:], pk.e) 132 } 133 134 // Pack packs the private key into buf. 135 func (sk *PrivateKey) Pack(buf *[PrivateKeySize]byte) { 136 var tmp [mode3.PrivateKeySize]byte 137 sk.d.Pack(&tmp) 138 copy(buf[:mode3.PrivateKeySize], tmp[:]) 139 copy(buf[mode3.PrivateKeySize:], sk.e.Seed()) 140 } 141 142 // Bytes packs the public key. 143 func (pk *PublicKey) Bytes() []byte { 144 return append(pk.d.Bytes(), pk.e...) 145 } 146 147 // Bytes packs the private key. 148 func (sk *PrivateKey) Bytes() []byte { 149 return append(sk.d.Bytes(), sk.e.Seed()...) 150 } 151 152 // MarshalBinary packs the public key. 153 func (pk *PublicKey) MarshalBinary() ([]byte, error) { 154 return pk.Bytes(), nil 155 } 156 157 // MarshalBinary packs the private key. 158 func (sk *PrivateKey) MarshalBinary() ([]byte, error) { 159 return sk.Bytes(), nil 160 } 161 162 // UnmarshalBinary the public key from data. 163 func (pk *PublicKey) UnmarshalBinary(data []byte) error { 164 if len(data) != PublicKeySize { 165 return errors.New("packed public key must be of eddilithium3.PublicKeySize bytes") 166 } 167 var buf [PublicKeySize]byte 168 copy(buf[:], data) 169 pk.Unpack(&buf) 170 return nil 171 } 172 173 // UnmarshalBinary unpacks the private key from data. 174 func (sk *PrivateKey) UnmarshalBinary(data []byte) error { 175 if len(data) != PrivateKeySize { 176 return errors.New("packed private key must be of eddilithium3.PrivateKeySize bytes") 177 } 178 var buf [PrivateKeySize]byte 179 copy(buf[:], data) 180 sk.Unpack(&buf) 181 return nil 182 } 183 184 func (sk *PrivateKey) Scheme() sign.Scheme { return sch } 185 func (pk *PublicKey) Scheme() sign.Scheme { return sch } 186 187 func (sk *PrivateKey) Equal(other crypto.PrivateKey) bool { 188 castOther, ok := other.(*PrivateKey) 189 if !ok { 190 return false 191 } 192 return castOther.e.Equal(sk.e) && castOther.d.Equal(&sk.d) 193 } 194 195 func (pk *PublicKey) Equal(other crypto.PublicKey) bool { 196 castOther, ok := other.(*PublicKey) 197 if !ok { 198 return false 199 } 200 return castOther.e.Equal(pk.e) && castOther.d.Equal(&pk.d) 201 } 202 203 // Sign signs the given message. 204 // 205 // opts.HashFunc() must return zero, which can be achieved by passing 206 // crypto.Hash(0) for opts. rand is ignored. Will only return an error 207 // if opts.HashFunc() is non-zero. 208 // 209 // This function is used to make PrivateKey implement the crypto.Signer 210 // interface. The package-level SignTo function might be more convenient 211 // to use. 212 func (sk *PrivateKey) Sign( 213 rand io.Reader, msg []byte, opts crypto.SignerOpts, 214 ) (signature []byte, err error) { 215 var sig [SignatureSize]byte 216 217 if opts.HashFunc() != crypto.Hash(0) { 218 return nil, errors.New("eddilithium3: cannot sign hashed message") 219 } 220 221 SignTo(sk, msg, sig[:]) 222 return sig[:], nil 223 } 224 225 // Public computes the public key corresponding to this private key. 226 // 227 // Returns a *PublicKey. The type crypto.PublicKey is used to make 228 // PrivateKey implement the crypto.Signer interface. 229 func (sk *PrivateKey) Public() crypto.PublicKey { 230 return &PublicKey{ 231 sk.e.Public().(ed448.PublicKey), 232 *sk.d.Public().(*mode3.PublicKey), 233 } 234 }