diff --git a/mldsa/mldsa44.go b/mldsa/mldsa44.go index 564e0ab..d43320e 100644 --- a/mldsa/mldsa44.go +++ b/mldsa/mldsa44.go @@ -380,6 +380,23 @@ func parsePrivateKey44(sk *PrivateKey44, b []byte) (*PrivateKey44, error) { return sk, nil } +// Sign generates a digital signature for the given message and context using the private key. +// It uses a random seed generated from the provided random source. +// +// Parameters: +// - rand: An io.Reader used to generate a random seed for signing. +// - message: The message to be signed. Must not be empty. +// - context: An optional context for domain separation. Must not exceed 255 bytes. +// +// Returns: +// - A byte slice containing the generated signature. +// - An error if the message is empty, the context is too long, or if there is an issue +// reading from the random source. +// +// Note: +// - The function uses SHAKE256 from the SHA-3 family for hashing. +// - The signing process involves generating a unique seed and a hash-based +// message digest (mu) before delegating to the internal signing function. func (sk *PrivateKey44) Sign(rand io.Reader, message, context []byte) ([]byte, error) { if len(message) == 0 { return nil, errors.New("mldsa: empty message") @@ -404,7 +421,11 @@ func (sk *PrivateKey44) Sign(rand io.Reader, message, context []byte) ([]byte, e return sk.signInternal(seed[:], mu[:]) } -func (sk *PrivateKey44) SignPreHash(rand io.Reader, message, context []byte, oid asn1.ObjectIdentifier) ([]byte, error) { +// SignWithPreHash generates a digital signature for the given message +// using the private key and additional context. It uses a given hashing algorithm +// from the OID to pre-hash the message before signing. +// It is similar to Sign but allows for pre-hashing the message. +func (sk *PrivateKey44) SignWithPreHash(rand io.Reader, message, context []byte, oid asn1.ObjectIdentifier) ([]byte, error) { if len(message) == 0 { return nil, errors.New("mldsa: empty message") } @@ -433,6 +454,7 @@ func (sk *PrivateKey44) SignPreHash(rand io.Reader, message, context []byte, oid return sk.signInternal(seed[:], mu[:]) } +// See FIPS 204, Algorithm 7 ML-DSA.Sign_internal() func (sk *PrivateKey44) signInternal(seed, mu []byte) ([]byte, error) { var s1NTT [l44]nttElement var s2NTT [k44]nttElement @@ -537,6 +559,8 @@ func (sk *PrivateKey44) signInternal(seed, mu []byte) ([]byte, error) { } } +// Verify checks the validity of a given signature for a message and context +// using the public key. func (pk *PublicKey44) Verify(sig []byte, message, context []byte) bool { if len(message) == 0 { return false @@ -560,7 +584,9 @@ func (pk *PublicKey44) Verify(sig []byte, message, context []byte) bool { return pk.verifyInternal(sig, mu[:]) } -func (pk *PublicKey44) VerifyPreHash(sig []byte, message, context []byte, oid asn1.ObjectIdentifier) bool { +// VerifyWithPreHash verifies a signature using a message and additional context. +// It uses a given hashing algorithm from the OID to pre-hash the message before verifying. +func (pk *PublicKey44) VerifyWithPreHash(sig []byte, message, context []byte, oid asn1.ObjectIdentifier) bool { if len(message) == 0 { return false } @@ -587,6 +613,7 @@ func (pk *PublicKey44) VerifyPreHash(sig []byte, message, context []byte, oid as return pk.verifyInternal(sig, mu[:]) } +// See FIPS 204, Algorithm 8 ML-DSA.Verify_internal() func (pk *PublicKey44) verifyInternal(sig, mu []byte) bool { // Decode the signature cTilde := sig[:lambda128/4] diff --git a/mldsa/mldsa44_test.go b/mldsa/mldsa44_test.go index 1e57abe..86b0f0f 100644 --- a/mldsa/mldsa44_test.go +++ b/mldsa/mldsa44_test.go @@ -220,7 +220,7 @@ var sigGenPreHash44InternalProjectionCases = []struct { }, } -func TestSignPreHash44(t *testing.T) { +func TestSignWithPreHash44(t *testing.T) { for _, c := range sigGenPreHash44InternalProjectionCases { sk, _ := hex.DecodeString(c.sk) pk, _ := hex.DecodeString(c.pk) @@ -231,7 +231,7 @@ func TestSignPreHash44(t *testing.T) { if err != nil { t.Fatalf("NewPrivateKey44 failed: %v", err) } - sig2, err := priv.SignPreHash(zeroReader, msg, context, c.oid) + sig2, err := priv.SignWithPreHash(zeroReader, msg, context, c.oid) if err != nil { t.Fatalf("failed to sign: %v", err) } @@ -248,7 +248,7 @@ func TestSignPreHash44(t *testing.T) { if err != nil { t.Fatalf("NewPublicKey44 failed: %v", err) } - if !pub.VerifyPreHash(sig, msg, context, c.oid) { + if !pub.VerifyWithPreHash(sig, msg, context, c.oid) { t.Error("signature verification failed") } } diff --git a/mldsa/mldsa65.go b/mldsa/mldsa65.go index 9a6e734..9ebb370 100644 --- a/mldsa/mldsa65.go +++ b/mldsa/mldsa65.go @@ -295,6 +295,23 @@ func parsePrivateKey65(sk *PrivateKey65, b []byte) (*PrivateKey65, error) { return sk, nil } +// Sign generates a digital signature for the given message and context using the private key. +// It uses a random seed generated from the provided random source. +// +// Parameters: +// - rand: An io.Reader used to generate a random seed for signing. +// - message: The message to be signed. Must not be empty. +// - context: An optional context for domain separation. Must not exceed 255 bytes. +// +// Returns: +// - A byte slice containing the generated signature. +// - An error if the message is empty, the context is too long, or if there is an issue +// reading from the random source. +// +// Note: +// - The function uses SHAKE256 from the SHA-3 family for hashing. +// - The signing process involves generating a unique seed and a hash-based +// message digest (mu) before delegating to the internal signing function. func (sk *PrivateKey65) Sign(rand io.Reader, message, context []byte) ([]byte, error) { if len(message) == 0 { return nil, errors.New("mldsa: empty message") @@ -319,7 +336,11 @@ func (sk *PrivateKey65) Sign(rand io.Reader, message, context []byte) ([]byte, e return sk.signInternal(seed[:], mu[:]) } -func (sk *PrivateKey65) SignPreHash(rand io.Reader, message, context []byte, oid asn1.ObjectIdentifier) ([]byte, error) { +// SignWithPreHash generates a digital signature for the given message +// using the private key and additional context. It uses a given hashing algorithm +// from the OID to pre-hash the message before signing. +// It is similar to Sign but allows for pre-hashing the message. +func (sk *PrivateKey65) SignWithPreHash(rand io.Reader, message, context []byte, oid asn1.ObjectIdentifier) ([]byte, error) { if len(message) == 0 { return nil, errors.New("mldsa: empty message") } @@ -348,6 +369,7 @@ func (sk *PrivateKey65) SignPreHash(rand io.Reader, message, context []byte, oid return sk.signInternal(seed[:], mu[:]) } +// See FIPS 204, Algorithm 7 ML-DSA.Sign_internal() func (sk *PrivateKey65) signInternal(seed, mu []byte) ([]byte, error) { var s1NTT [l65]nttElement var s2NTT [k65]nttElement @@ -452,6 +474,8 @@ func (sk *PrivateKey65) signInternal(seed, mu []byte) ([]byte, error) { } } +// Verify checks the validity of a given signature for a message and context +// using the public key. func (pk *PublicKey65) Verify(sig []byte, message, context []byte) bool { if len(message) == 0 { return false @@ -473,7 +497,9 @@ func (pk *PublicKey65) Verify(sig []byte, message, context []byte) bool { return pk.verifyInternal(sig, mu[:]) } -func (pk *PublicKey65) VerifyPreHash(sig []byte, message, context []byte, oid asn1.ObjectIdentifier) bool { +// VerifyWithPreHash verifies a signature using a message and additional context. +// It uses a given hashing algorithm from the OID to pre-hash the message before verifying. +func (pk *PublicKey65) VerifyWithPreHash(sig []byte, message, context []byte, oid asn1.ObjectIdentifier) bool { if len(message) == 0 { return false } @@ -500,6 +526,7 @@ func (pk *PublicKey65) VerifyPreHash(sig []byte, message, context []byte, oid as return pk.verifyInternal(sig, mu[:]) } +// See FIPS 204, Algorithm 8 ML-DSA.Verify_internal() func (pk *PublicKey65) verifyInternal(sig, mu []byte) bool { // Decode the signature cTilde := sig[:lambda192/4] diff --git a/mldsa/mldsa65_test.go b/mldsa/mldsa65_test.go index 2a2fdb9..4a69474 100644 --- a/mldsa/mldsa65_test.go +++ b/mldsa/mldsa65_test.go @@ -220,7 +220,7 @@ var sigGenPreHash65InternalProjectionCases = []struct { }, } -func TestSignPreHash65(t *testing.T) { +func TestSignWithPreHash65(t *testing.T) { for _, c := range sigGenPreHash65InternalProjectionCases { sk, _ := hex.DecodeString(c.sk) pk, _ := hex.DecodeString(c.pk) @@ -231,7 +231,7 @@ func TestSignPreHash65(t *testing.T) { if err != nil { t.Fatalf("NewPrivateKey65 failed: %v", err) } - sig2, err := priv.SignPreHash(zeroReader, msg, context, c.oid) + sig2, err := priv.SignWithPreHash(zeroReader, msg, context, c.oid) if err != nil { t.Fatalf("failed to sign: %v", err) } @@ -248,7 +248,7 @@ func TestSignPreHash65(t *testing.T) { if err != nil { t.Fatalf("NewPublicKey65 failed: %v", err) } - if !pub.VerifyPreHash(sig, msg, context, c.oid) { + if !pub.VerifyWithPreHash(sig, msg, context, c.oid) { t.Error("signature verification failed") } } diff --git a/mldsa/mldsa87.go b/mldsa/mldsa87.go index 98d99d6..68749a0 100644 --- a/mldsa/mldsa87.go +++ b/mldsa/mldsa87.go @@ -295,6 +295,23 @@ func parsePrivateKey87(sk *PrivateKey87, b []byte) (*PrivateKey87, error) { return sk, nil } +// Sign generates a digital signature for the given message and context using the private key. +// It uses a random seed generated from the provided random source. +// +// Parameters: +// - rand: An io.Reader used to generate a random seed for signing. +// - message: The message to be signed. Must not be empty. +// - context: An optional context for domain separation. Must not exceed 255 bytes. +// +// Returns: +// - A byte slice containing the generated signature. +// - An error if the message is empty, the context is too long, or if there is an issue +// reading from the random source. +// +// Note: +// - The function uses SHAKE256 from the SHA-3 family for hashing. +// - The signing process involves generating a unique seed and a hash-based +// message digest (mu) before delegating to the internal signing function. func (sk *PrivateKey87) Sign(rand io.Reader, message, context []byte) ([]byte, error) { if len(message) == 0 { return nil, errors.New("mldsa: empty message") @@ -319,7 +336,11 @@ func (sk *PrivateKey87) Sign(rand io.Reader, message, context []byte) ([]byte, e return sk.signInternal(seed[:], mu[:]) } -func (sk *PrivateKey87) SignPreHash(rand io.Reader, message, context []byte, oid asn1.ObjectIdentifier) ([]byte, error) { +// SignWithPreHash generates a digital signature for the given message +// using the private key and additional context. It uses a given hashing algorithm +// from the OID to pre-hash the message before signing. +// It is similar to Sign but allows for pre-hashing the message. +func (sk *PrivateKey87) SignWithPreHash(rand io.Reader, message, context []byte, oid asn1.ObjectIdentifier) ([]byte, error) { if len(message) == 0 { return nil, errors.New("mldsa: empty message") } @@ -348,6 +369,7 @@ func (sk *PrivateKey87) SignPreHash(rand io.Reader, message, context []byte, oid return sk.signInternal(seed[:], mu[:]) } +// See FIPS 204, Algorithm 7 ML-DSA.Sign_internal() func (sk *PrivateKey87) signInternal(seed, mu []byte) ([]byte, error) { var s1NTT [l87]nttElement var s2NTT [k87]nttElement @@ -452,6 +474,8 @@ func (sk *PrivateKey87) signInternal(seed, mu []byte) ([]byte, error) { } } +// Verify checks the validity of a given signature for a message and context +// using the public key. func (pk *PublicKey87) Verify(sig []byte, message, context []byte) bool { if len(message) == 0 { return false @@ -475,7 +499,9 @@ func (pk *PublicKey87) Verify(sig []byte, message, context []byte) bool { return pk.verifyInternal(sig, mu[:]) } -func (pk *PublicKey87) VerifyPreHash(sig []byte, message, context []byte, oid asn1.ObjectIdentifier) bool { +// VerifyWithPreHash verifies a signature using a message and additional context. +// It uses a given hashing algorithm from the OID to pre-hash the message before verifying. +func (pk *PublicKey87) VerifyWithPreHash(sig []byte, message, context []byte, oid asn1.ObjectIdentifier) bool { if len(message) == 0 { return false } @@ -502,6 +528,7 @@ func (pk *PublicKey87) VerifyPreHash(sig []byte, message, context []byte, oid as return pk.verifyInternal(sig, mu[:]) } +// See FIPS 204, Algorithm 8 ML-DSA.Verify_internal() func (pk *PublicKey87) verifyInternal(sig, mu []byte) bool { // Decode the signature cTilde := sig[:lambda256/4] diff --git a/mldsa/mldsa87_test.go b/mldsa/mldsa87_test.go index 2e7ed86..74c5476 100644 --- a/mldsa/mldsa87_test.go +++ b/mldsa/mldsa87_test.go @@ -172,7 +172,7 @@ var sigGenPreHash87InternalProjectionCases = []struct { }, } -func TestSignPreHash87(t *testing.T) { +func TestSignWithPreHash87(t *testing.T) { for _, c := range sigGenPreHash87InternalProjectionCases { sk, _ := hex.DecodeString(c.sk) pk, _ := hex.DecodeString(c.pk) @@ -183,7 +183,7 @@ func TestSignPreHash87(t *testing.T) { if err != nil { t.Fatalf("NewPrivateKey87 failed: %v", err) } - sig2, err := priv.SignPreHash(zeroReader, msg, context, c.oid) + sig2, err := priv.SignWithPreHash(zeroReader, msg, context, c.oid) if err != nil { t.Fatalf("failed to sign: %v", err) } @@ -200,7 +200,7 @@ func TestSignPreHash87(t *testing.T) { if err != nil { t.Fatalf("NewPublicKey87 failed: %v", err) } - if !pub.VerifyPreHash(sig, msg, context, c.oid) { + if !pub.VerifyWithPreHash(sig, msg, context, c.oid) { t.Error("signature verification failed") } }