mirror of
https://github.com/emmansun/gmsm.git
synced 2025-09-23 07:13:49 +08:00
mldsa,slhdsa: crypto.Signer assertion
This commit is contained in:
parent
fd2eedf24b
commit
2435170a2f
@ -243,3 +243,19 @@ func vectorCountOnes(a []ringElement) int {
|
||||
}
|
||||
return oneCount
|
||||
}
|
||||
|
||||
func constantTimeEqualRingElement(a, b ringElement) int {
|
||||
var res int32
|
||||
for i := range a {
|
||||
res |= int32(a[i] ^ b[i])
|
||||
}
|
||||
return subtle.ConstantTimeByteEq(byte(res|(-res)>>31), 0)
|
||||
}
|
||||
|
||||
func constantTimeEqualRingElementArray(a, b []ringElement) int {
|
||||
eq := 1
|
||||
for i := range a {
|
||||
eq &= constantTimeEqualRingElement(a[i], b[i])
|
||||
}
|
||||
return eq
|
||||
}
|
||||
|
@ -101,6 +101,9 @@ const (
|
||||
sigEncodedLen87 = lambda256/4 + encodingSize20*l87 + omega75 + k87
|
||||
)
|
||||
|
||||
var _ crypto.Signer = (*PrivateKey44)(nil)
|
||||
var _ crypto.Signer = (*Key44)(nil)
|
||||
|
||||
// A PrivateKey44 is the private key for the ML-DSA-44 signature scheme.
|
||||
type PrivateKey44 struct {
|
||||
rho [32]byte // public random seed
|
||||
@ -118,10 +121,10 @@ type PrivateKey44 struct {
|
||||
t1Once sync.Once
|
||||
}
|
||||
|
||||
// PublicKey returns the public key corresponding to the private key.
|
||||
// Public returns the public key corresponding to the private key.
|
||||
// Although we can derive the public key from the private key,
|
||||
// but we do NOT need to derive it at most of the time.
|
||||
func (sk *PrivateKey44) PublicKey() crypto.PublicKey {
|
||||
func (sk *PrivateKey44) Public() crypto.PublicKey {
|
||||
sk.ensureT1()
|
||||
return &PublicKey44{
|
||||
rho: sk.rho,
|
||||
@ -187,9 +190,9 @@ type PublicKey44 struct {
|
||||
nttOnce sync.Once
|
||||
}
|
||||
|
||||
// PublicKey generates and returns the corresponding public key for the given
|
||||
// Public generates and returns the corresponding public key for the given
|
||||
// Key44 instance.
|
||||
func (sk *Key44) PublicKey() *PublicKey44 {
|
||||
func (sk *Key44) Public() crypto.PublicKey {
|
||||
return &PublicKey44{
|
||||
rho: sk.rho,
|
||||
t1: sk.t1,
|
||||
@ -210,9 +213,9 @@ func (pk *PublicKey44) Equal(x crypto.PublicKey) bool {
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
b1 := pk.Bytes()
|
||||
b2 := xx.Bytes()
|
||||
return subtle.ConstantTimeCompare(b1, b2) == 1
|
||||
eq := subtle.ConstantTimeCompare(pk.rho[:], xx.rho[:]) &
|
||||
constantTimeEqualRingElementArray(pk.t1[:], xx.t1[:])
|
||||
return eq == 1
|
||||
}
|
||||
|
||||
// Bytes converts the PublicKey44 instance into a byte slice.
|
||||
@ -271,9 +274,13 @@ func (sk *PrivateKey44) Equal(x any) bool {
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
b1 := sk.Bytes()
|
||||
b2 := xx.Bytes()
|
||||
return subtle.ConstantTimeCompare(b1, b2) == 1
|
||||
eq := subtle.ConstantTimeCompare(sk.rho[:], xx.rho[:]) &
|
||||
subtle.ConstantTimeCompare(sk.k[:], xx.k[:]) &
|
||||
subtle.ConstantTimeCompare(sk.tr[:], xx.tr[:]) &
|
||||
constantTimeEqualRingElementArray(sk.s1[:], xx.s1[:]) &
|
||||
constantTimeEqualRingElementArray(sk.s2[:], xx.s2[:]) &
|
||||
constantTimeEqualRingElementArray(sk.t0[:], xx.t0[:])
|
||||
return eq == 1
|
||||
}
|
||||
|
||||
// GenerateKey44 generates a new Key44 (ML-DSA-44) using the provided random source.
|
||||
@ -363,7 +370,7 @@ func dsaKeyGen44(sk *Key44, xi *[32]byte) {
|
||||
}
|
||||
}
|
||||
H.Reset()
|
||||
ek := sk.PublicKey().Bytes()
|
||||
ek := sk.Public().(*PublicKey44).Bytes()
|
||||
H.Write(ek)
|
||||
H.Read(sk.tr[:])
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ func TestKeyGen44(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("NewPrivateKey44 failed: %v", err)
|
||||
}
|
||||
pub := priv.PublicKey()
|
||||
pub := priv.Public().(*PublicKey44)
|
||||
pubBytes := pub.Bytes()
|
||||
if !bytes.Equal(pubBytes, pk) {
|
||||
t.Errorf("Public key mismatch: got %x, want %x", pubBytes, pk)
|
||||
@ -70,7 +70,7 @@ func TestKeyGen44(t *testing.T) {
|
||||
if !priv.Equal(priv2) {
|
||||
t.Errorf("Private key not equal: got %x, want %x", privBytes, priv2.Bytes())
|
||||
}
|
||||
pub3 := priv2.PublicKey()
|
||||
pub3 := priv2.Public()
|
||||
if !pub.Equal(pub3) {
|
||||
t.Errorf("Public key from private key not equal")
|
||||
}
|
||||
@ -127,6 +127,7 @@ func TestSign44(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("NewPrivateKey44 failed: %v", err)
|
||||
}
|
||||
|
||||
sig2, err := priv.signInternal(seed[:], mu)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to sign: %v", err)
|
||||
|
@ -17,6 +17,9 @@ import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
var _ crypto.Signer = (*PrivateKey65)(nil)
|
||||
var _ crypto.Signer = (*Key65)(nil)
|
||||
|
||||
// A PrivateKey65 is the private key for the ML-DSA-65 signature scheme.
|
||||
type PrivateKey65 struct {
|
||||
rho [32]byte // public random seed
|
||||
@ -34,10 +37,10 @@ type PrivateKey65 struct {
|
||||
t1Once sync.Once
|
||||
}
|
||||
|
||||
// PublicKey returns the public key corresponding to the private key.
|
||||
// Public returns the public key corresponding to the private key.
|
||||
// Although we can derive the public key from the private key,
|
||||
// but we do NOT need to derive it at most of the time.
|
||||
func (sk *PrivateKey65) PublicKey() crypto.PublicKey {
|
||||
func (sk *PrivateKey65) Public() crypto.PublicKey {
|
||||
sk.ensureT1()
|
||||
return &PublicKey65{
|
||||
rho: sk.rho,
|
||||
@ -103,9 +106,9 @@ type PublicKey65 struct {
|
||||
nttOnce sync.Once
|
||||
}
|
||||
|
||||
// PublicKey generates and returns the corresponding public key for the given
|
||||
// Public generates and returns the corresponding public key for the given
|
||||
// Key65 instance.
|
||||
func (sk *Key65) PublicKey() *PublicKey65 {
|
||||
func (sk *Key65) Public() crypto.PublicKey {
|
||||
return &PublicKey65{
|
||||
rho: sk.rho,
|
||||
t1: sk.t1,
|
||||
@ -126,9 +129,9 @@ func (pk *PublicKey65) Equal(x crypto.PublicKey) bool {
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
b1 := pk.Bytes()
|
||||
b2 := xx.Bytes()
|
||||
return subtle.ConstantTimeCompare(b1, b2) == 1
|
||||
eq := subtle.ConstantTimeCompare(pk.rho[:], xx.rho[:]) &
|
||||
constantTimeEqualRingElementArray(pk.t1[:], xx.t1[:])
|
||||
return eq == 1
|
||||
}
|
||||
|
||||
// Bytes converts the PublicKey65 instance into a byte slice.
|
||||
@ -187,9 +190,13 @@ func (sk *PrivateKey65) Equal(x any) bool {
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
b1 := sk.Bytes()
|
||||
b2 := xx.Bytes()
|
||||
return subtle.ConstantTimeCompare(b1, b2) == 1
|
||||
eq := subtle.ConstantTimeCompare(sk.rho[:], xx.rho[:]) &
|
||||
subtle.ConstantTimeCompare(sk.k[:], xx.k[:]) &
|
||||
subtle.ConstantTimeCompare(sk.tr[:], xx.tr[:]) &
|
||||
constantTimeEqualRingElementArray(sk.s1[:], xx.s1[:]) &
|
||||
constantTimeEqualRingElementArray(sk.s2[:], xx.s2[:]) &
|
||||
constantTimeEqualRingElementArray(sk.t0[:], xx.t0[:])
|
||||
return eq == 1
|
||||
}
|
||||
|
||||
// GenerateKey65 generates a new Key65 (ML-DSA-65) using the provided random source.
|
||||
@ -279,7 +286,7 @@ func dsaKeyGen65(sk *Key65, xi *[32]byte) {
|
||||
}
|
||||
}
|
||||
H.Reset()
|
||||
ek := sk.PublicKey().Bytes()
|
||||
ek := sk.Public().(*PublicKey65).Bytes()
|
||||
H.Write(ek)
|
||||
H.Read(sk.tr[:])
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ func TestKeyGen65(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("NewPrivateKey65 failed: %v", err)
|
||||
}
|
||||
pub := priv.PublicKey()
|
||||
pub := priv.Public().(*PublicKey65)
|
||||
pubBytes := pub.Bytes()
|
||||
if !bytes.Equal(pubBytes, pk) {
|
||||
t.Errorf("Public key mismatch: got %x, want %x", pubBytes, pk)
|
||||
@ -70,7 +70,7 @@ func TestKeyGen65(t *testing.T) {
|
||||
if !priv.Equal(priv2) {
|
||||
t.Errorf("Private key not equal: got %x, want %x", privBytes, priv2.Bytes())
|
||||
}
|
||||
pub3 := priv2.PublicKey()
|
||||
pub3 := priv2.Public()
|
||||
if !pub.Equal(pub3) {
|
||||
t.Errorf("Public key from private key not equal")
|
||||
}
|
||||
|
@ -17,6 +17,9 @@ import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
var _ crypto.Signer = (*PrivateKey87)(nil)
|
||||
var _ crypto.Signer = (*Key87)(nil)
|
||||
|
||||
// A PrivateKey87 is the private key for the ML-DSA-87 signature scheme.
|
||||
type PrivateKey87 struct {
|
||||
rho [32]byte // public random seed
|
||||
@ -34,10 +37,10 @@ type PrivateKey87 struct {
|
||||
t1Once sync.Once
|
||||
}
|
||||
|
||||
// PublicKey returns the public key corresponding to the private key.
|
||||
// Public returns the public key corresponding to the private key.
|
||||
// Although we can derive the public key from the private key,
|
||||
// but we do NOT need to derive it at most of the time.
|
||||
func (sk *PrivateKey87) PublicKey() crypto.PublicKey {
|
||||
func (sk *PrivateKey87) Public() crypto.PublicKey {
|
||||
sk.ensureT1()
|
||||
return &PublicKey87{
|
||||
rho: sk.rho,
|
||||
@ -103,9 +106,9 @@ type PublicKey87 struct {
|
||||
nttOnce sync.Once
|
||||
}
|
||||
|
||||
// PublicKey generates and returns the corresponding public key for the given
|
||||
// Public generates and returns the corresponding public key for the given
|
||||
// Key87 instance.
|
||||
func (sk *Key87) PublicKey() *PublicKey87 {
|
||||
func (sk *Key87) Public() crypto.PublicKey {
|
||||
return &PublicKey87{
|
||||
rho: sk.rho,
|
||||
t1: sk.t1,
|
||||
@ -126,9 +129,9 @@ func (pk *PublicKey87) Equal(x crypto.PublicKey) bool {
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
b1 := pk.Bytes()
|
||||
b2 := xx.Bytes()
|
||||
return subtle.ConstantTimeCompare(b1, b2) == 1
|
||||
eq := subtle.ConstantTimeCompare(pk.rho[:], xx.rho[:]) &
|
||||
constantTimeEqualRingElementArray(pk.t1[:], xx.t1[:])
|
||||
return eq == 1
|
||||
}
|
||||
|
||||
// Bytes converts the PublicKey87 instance into a byte slice.
|
||||
@ -187,9 +190,13 @@ func (sk *PrivateKey87) Equal(x any) bool {
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
b1 := sk.Bytes()
|
||||
b2 := xx.Bytes()
|
||||
return subtle.ConstantTimeCompare(b1, b2) == 1
|
||||
eq := subtle.ConstantTimeCompare(sk.rho[:], xx.rho[:]) &
|
||||
subtle.ConstantTimeCompare(sk.k[:], xx.k[:]) &
|
||||
subtle.ConstantTimeCompare(sk.tr[:], xx.tr[:]) &
|
||||
constantTimeEqualRingElementArray(sk.s1[:], xx.s1[:]) &
|
||||
constantTimeEqualRingElementArray(sk.s2[:], xx.s2[:]) &
|
||||
constantTimeEqualRingElementArray(sk.t0[:], xx.t0[:])
|
||||
return eq == 1
|
||||
}
|
||||
|
||||
// GenerateKey87 generates a new Key87 (ML-DSA-87) using the provided random source.
|
||||
@ -279,7 +286,7 @@ func dsaKeyGen87(sk *Key87, xi *[32]byte) {
|
||||
}
|
||||
}
|
||||
H.Reset()
|
||||
ek := sk.PublicKey().Bytes()
|
||||
ek := sk.Public().(*PublicKey87).Bytes()
|
||||
H.Write(ek)
|
||||
H.Read(sk.tr[:])
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ func TestKeyGen87(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("NewPrivateKey65 failed: %v", err)
|
||||
}
|
||||
pub := priv.PublicKey()
|
||||
pub := priv.Public().(*PublicKey87)
|
||||
pubBytes := pub.Bytes()
|
||||
if !bytes.Equal(pubBytes, pk) {
|
||||
t.Errorf("Public key mismatch: got %x, want %x", pubBytes, pk)
|
||||
@ -70,7 +70,7 @@ func TestKeyGen87(t *testing.T) {
|
||||
if !priv.Equal(priv2) {
|
||||
t.Errorf("Private key not equal: got %x, want %x", privBytes, priv2.Bytes())
|
||||
}
|
||||
pub3 := priv2.PublicKey()
|
||||
pub3 := priv2.Public()
|
||||
if !pub.Equal(pub3) {
|
||||
t.Errorf("Public key from private key not equal")
|
||||
}
|
||||
|
@ -7,18 +7,42 @@
|
||||
package slhdsa
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"errors"
|
||||
"io"
|
||||
)
|
||||
|
||||
var _ crypto.Signer = (*PrivateKey)(nil)
|
||||
|
||||
type Options struct {
|
||||
Context []byte
|
||||
AddRand []byte // optional randomness to be added to the signature. If nil, the signature is deterministic.
|
||||
}
|
||||
|
||||
func (opts *Options) HashFunc() crypto.Hash {
|
||||
return crypto.Hash(0)
|
||||
}
|
||||
|
||||
// Sign produces a signature of the message using the private key.
|
||||
// It is a wrapper around the SignMessage method, implementing the crypto.Signer interface.
|
||||
func (sk *PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOpts) ([]byte, error) {
|
||||
return sk.SignMessage(rand, message, opts)
|
||||
}
|
||||
|
||||
// Sign generates a pure SLH-DSA signature for the given message.
|
||||
// The signature is deterministic if the addRand parameter is nil.
|
||||
// If addRand is not nil, it must be of the same length as n.
|
||||
//
|
||||
// See FIPS 205 Algorithm 22 slh_sign
|
||||
func (sk *PrivateKey) Sign(message, context, addRand []byte) ([]byte, error) {
|
||||
func (sk *PrivateKey) SignMessage(rand io.Reader, message []byte, opts crypto.SignerOpts) ([]byte, error) {
|
||||
if len(message) == 0 {
|
||||
return nil, errors.New("slhdsa: empty message")
|
||||
}
|
||||
var context, addRand []byte
|
||||
if opts, ok := opts.(*Options); ok {
|
||||
context = opts.Context
|
||||
addRand = opts.AddRand
|
||||
}
|
||||
if len(addRand) > 0 && len(addRand) != int(sk.params.n) {
|
||||
return nil, errors.New("slhdsa: addrnd should be nil (deterministic variant) or of length n")
|
||||
}
|
||||
@ -85,10 +109,14 @@ func (sk *PrivateKey) signInternal(msgPrefix, message, addRand []byte) ([]byte,
|
||||
// Verify verifies a pure SLH-DSA signature for the given message.
|
||||
//
|
||||
// See FIPS 205 Algorithm 24 slh_verify
|
||||
func (pk *PublicKey) Verify(signature, message, context []byte) bool {
|
||||
func (pk *PublicKey) VerifyWithOptions(signature, message []byte, opts crypto.SignerOpts) bool {
|
||||
if len(message) == 0 {
|
||||
return false
|
||||
}
|
||||
var context []byte
|
||||
if opts, ok := opts.(*Options); ok {
|
||||
context = opts.Context
|
||||
}
|
||||
if len(context) > maxContextLen {
|
||||
return false
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ func testData(t *testing.T, filename string, tc *slhtest) {
|
||||
if err != nil {
|
||||
t.Fatalf("%v NewPrivateKey(%x) = %v", filename, skBytes, err)
|
||||
}
|
||||
sig2, err := privKey.Sign(message, context, addRand)
|
||||
sig2, err := privKey.Sign(nil, message, &Options{context, addRand})
|
||||
if err != nil {
|
||||
t.Fatalf("%v Sign(%x,%x) = %v", filename, message, context, err)
|
||||
}
|
||||
@ -104,7 +104,7 @@ func testData(t *testing.T, filename string, tc *slhtest) {
|
||||
if err != nil {
|
||||
t.Fatalf("%v NewPublicKey(%x) = %v", filename, pkBytes, err)
|
||||
}
|
||||
if !pub.Verify(sigOriginal, message, context) {
|
||||
if !pub.VerifyWithOptions(sigOriginal, message, &Options{Context: context}) {
|
||||
t.Errorf("%v Verify() = false, want true", filename)
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
package slhdsa
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/sha256"
|
||||
"crypto/sha3"
|
||||
"crypto/sha512"
|
||||
@ -69,7 +70,7 @@ func (sk *PrivateKey) Bytes() []byte {
|
||||
}
|
||||
|
||||
// Public returns the public key of the private key.
|
||||
func (sk *PrivateKey) Public() *PublicKey {
|
||||
func (sk *PrivateKey) Public() crypto.PublicKey {
|
||||
return &sk.PublicKey
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user