mldsa: supports prehash dsa

This commit is contained in:
Sun Yimin 2025-05-07 15:08:36 +08:00 committed by GitHub
parent dfd4143c65
commit 834873f0e8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 465 additions and 2 deletions

View File

@ -7,17 +7,18 @@
// Package mldsa implements the quantum-resistant digital signature algorithm // Package mldsa implements the quantum-resistant digital signature algorithm
// ML-DSA (Module-Lattice-Based Digital Signature Standard) as specified in [NIST FIPS 204]. // ML-DSA (Module-Lattice-Based Digital Signature Standard) as specified in [NIST FIPS 204].
// //
// [NIST FIPS 204]: https://doi.org/10.6028/NIST.FIPS.204
//
// This implementations referenced OpenSSL's implementation of ML-DSA and part of Golang ML-KEM // This implementations referenced OpenSSL's implementation of ML-DSA and part of Golang ML-KEM
// [OpenSSL ML-DSA]: https://github.com/openssl/openssl/blob/master/crypto/ml_dsa // [OpenSSL ML-DSA]: https://github.com/openssl/openssl/blob/master/crypto/ml_dsa
// [Golang ML-KEM]: https://github.com/golang/go/blob/master/src/crypto/internal/fips140/mlkem // [Golang ML-KEM]: https://github.com/golang/go/blob/master/src/crypto/internal/fips140/mlkem
//
// [NIST FIPS 204]: https://doi.org/10.6028/NIST.FIPS.204
package mldsa package mldsa
import ( import (
"crypto" "crypto"
"crypto/sha3" "crypto/sha3"
"crypto/subtle" "crypto/subtle"
"encoding/asn1"
"errors" "errors"
"io" "io"
) )
@ -403,6 +404,35 @@ func (sk *PrivateKey44) Sign(rand io.Reader, message, context []byte) ([]byte, e
return sk.signInternal(seed[:], mu[:]) return sk.signInternal(seed[:], mu[:])
} }
func (sk *PrivateKey44) SignPreHash(rand io.Reader, message, context []byte, oid asn1.ObjectIdentifier) ([]byte, error) {
if len(message) == 0 {
return nil, errors.New("mldsa: empty message")
}
if len(context) > 255 {
return nil, errors.New("mldsa: context too long")
}
preHashValue, err := preHash(oid, message)
if err != nil {
return nil, err
}
var seed [SeedSize]byte
if _, err := io.ReadFull(rand, seed[:]); err != nil {
return nil, err
}
H := sha3.NewSHAKE256()
H.Write(sk.tr[:])
H.Write([]byte{1, byte(len(context))})
if len(context) > 0 {
H.Write(context)
}
H.Write(preHashValue)
var mu [64]byte
H.Read(mu[:])
return sk.signInternal(seed[:], mu[:])
}
func (sk *PrivateKey44) signInternal(seed, mu []byte) ([]byte, error) { func (sk *PrivateKey44) signInternal(seed, mu []byte) ([]byte, error) {
var s1NTT [l44]nttElement var s1NTT [l44]nttElement
var s2NTT [k44]nttElement var s2NTT [k44]nttElement
@ -530,6 +560,33 @@ func (pk *PublicKey44) Verify(sig []byte, message, context []byte) bool {
return pk.verifyInternal(sig, mu[:]) return pk.verifyInternal(sig, mu[:])
} }
func (pk *PublicKey44) VerifyPreHash(sig []byte, message, context []byte, oid asn1.ObjectIdentifier) bool {
if len(message) == 0 {
return false
}
if len(context) > 255 {
return false
}
if len(sig) != sigEncodedLen44 {
return false
}
preHashValue, err := preHash(oid, message)
if err != nil {
return false
}
H := sha3.NewSHAKE256()
H.Write(pk.tr[:])
H.Write([]byte{1, byte(len(context))})
if len(context) > 0 {
H.Write(context)
}
H.Write(preHashValue)
var mu [64]byte
H.Read(mu[:])
return pk.verifyInternal(sig, mu[:])
}
func (pk *PublicKey44) verifyInternal(sig, mu []byte) bool { func (pk *PublicKey44) verifyInternal(sig, mu []byte) bool {
// Decode the signature // Decode the signature
cTilde := sig[:lambda128/4] cTilde := sig[:lambda128/4]

File diff suppressed because one or more lines are too long

View File

@ -10,6 +10,7 @@ import (
"crypto" "crypto"
"crypto/sha3" "crypto/sha3"
"crypto/subtle" "crypto/subtle"
"encoding/asn1"
"errors" "errors"
"io" "io"
) )
@ -318,6 +319,35 @@ func (sk *PrivateKey65) Sign(rand io.Reader, message, context []byte) ([]byte, e
return sk.signInternal(seed[:], mu[:]) return sk.signInternal(seed[:], mu[:])
} }
func (sk *PrivateKey65) SignPreHash(rand io.Reader, message, context []byte, oid asn1.ObjectIdentifier) ([]byte, error) {
if len(message) == 0 {
return nil, errors.New("mldsa: empty message")
}
if len(context) > 255 {
return nil, errors.New("mldsa: context too long")
}
preHashValue, err := preHash(oid, message)
if err != nil {
return nil, err
}
var seed [SeedSize]byte
if _, err := io.ReadFull(rand, seed[:]); err != nil {
return nil, err
}
H := sha3.NewSHAKE256()
H.Write(sk.tr[:])
H.Write([]byte{1, byte(len(context))})
if len(context) > 0 {
H.Write(context)
}
H.Write(preHashValue)
var mu [64]byte
H.Read(mu[:])
return sk.signInternal(seed[:], mu[:])
}
func (sk *PrivateKey65) signInternal(seed, mu []byte) ([]byte, error) { func (sk *PrivateKey65) signInternal(seed, mu []byte) ([]byte, error) {
var s1NTT [l65]nttElement var s1NTT [l65]nttElement
var s2NTT [k65]nttElement var s2NTT [k65]nttElement
@ -443,6 +473,33 @@ func (pk *PublicKey65) Verify(sig []byte, message, context []byte) bool {
return pk.verifyInternal(sig, mu[:]) return pk.verifyInternal(sig, mu[:])
} }
func (pk *PublicKey65) VerifyPreHash(sig []byte, message, context []byte, oid asn1.ObjectIdentifier) bool {
if len(message) == 0 {
return false
}
if len(context) > 255 {
return false
}
if len(sig) != sigEncodedLen65 {
return false
}
preHashValue, err := preHash(oid, message)
if err != nil {
return false
}
H := sha3.NewSHAKE256()
H.Write(pk.tr[:])
H.Write([]byte{1, byte(len(context))})
if len(context) > 0 {
H.Write(context)
}
H.Write(preHashValue)
var mu [64]byte
H.Read(mu[:])
return pk.verifyInternal(sig, mu[:])
}
func (pk *PublicKey65) verifyInternal(sig, mu []byte) bool { func (pk *PublicKey65) verifyInternal(sig, mu []byte) bool {
// Decode the signature // Decode the signature
cTilde := sig[:lambda192/4] cTilde := sig[:lambda192/4]

File diff suppressed because one or more lines are too long

View File

@ -10,6 +10,7 @@ import (
"crypto" "crypto"
"crypto/sha3" "crypto/sha3"
"crypto/subtle" "crypto/subtle"
"encoding/asn1"
"errors" "errors"
"io" "io"
) )
@ -318,6 +319,35 @@ func (sk *PrivateKey87) Sign(rand io.Reader, message, context []byte) ([]byte, e
return sk.signInternal(seed[:], mu[:]) return sk.signInternal(seed[:], mu[:])
} }
func (sk *PrivateKey87) SignPreHash(rand io.Reader, message, context []byte, oid asn1.ObjectIdentifier) ([]byte, error) {
if len(message) == 0 {
return nil, errors.New("mldsa: empty message")
}
if len(context) > 255 {
return nil, errors.New("mldsa: context too long")
}
preHashValue, err := preHash(oid, message)
if err != nil {
return nil, err
}
var seed [SeedSize]byte
if _, err := io.ReadFull(rand, seed[:]); err != nil {
return nil, err
}
H := sha3.NewSHAKE256()
H.Write(sk.tr[:])
H.Write([]byte{1, byte(len(context))})
if len(context) > 0 {
H.Write(context)
}
H.Write(preHashValue)
var mu [64]byte
H.Read(mu[:])
return sk.signInternal(seed[:], mu[:])
}
func (sk *PrivateKey87) signInternal(seed, mu []byte) ([]byte, error) { func (sk *PrivateKey87) signInternal(seed, mu []byte) ([]byte, error) {
var s1NTT [l87]nttElement var s1NTT [l87]nttElement
var s2NTT [k87]nttElement var s2NTT [k87]nttElement
@ -445,6 +475,33 @@ func (pk *PublicKey87) Verify(sig []byte, message, context []byte) bool {
return pk.verifyInternal(sig, mu[:]) return pk.verifyInternal(sig, mu[:])
} }
func (pk *PublicKey87) VerifyPreHash(sig []byte, message, context []byte, oid asn1.ObjectIdentifier) bool {
if len(message) == 0 {
return false
}
if len(context) > 255 {
return false
}
if len(sig) != sigEncodedLen87 {
return false
}
preHashValue, err := preHash(oid, message)
if err != nil {
return false
}
H := sha3.NewSHAKE256()
H.Write(pk.tr[:])
H.Write([]byte{1, byte(len(context))})
if len(context) > 0 {
H.Write(context)
}
H.Write(preHashValue)
var mu [64]byte
H.Read(mu[:])
return pk.verifyInternal(sig, mu[:])
}
func (pk *PublicKey87) verifyInternal(sig, mu []byte) bool { func (pk *PublicKey87) verifyInternal(sig, mu []byte) bool {
// Decode the signature // Decode the signature
cTilde := sig[:lambda256/4] cTilde := sig[:lambda256/4]

File diff suppressed because one or more lines are too long