gmsm/slhdsa/parameterset.go
2025-06-19 16:37:53 +08:00

148 lines
5.8 KiB
Go

// Copyright 2025 Sun Yimin. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
//go:build go1.24
package slhdsa
import "io"
const (
maxN = 32
maxM = 49
maxK = 35
maxA = 9
maxKTimesA = maxK * maxA
maxWotsLen = 2*maxN + 3
maxContextLen = 255
)
type params struct {
alg string
isShake int
isSM3 int
n uint32 // Security parameter (Hash output size in bytes) (16, 24, 32)
len uint32 // 2*n + 3
h uint32 // The total height of the tree (63, 64, 66, 68). #keypairs = 2^h
d uint32 // The number of tree layers (7, 8, 17, 22)
hm uint32 // The height (h') of each merkle tree. (h = hm * d )
a uint32 // Height of a FORS tree
k uint32 // The number of FORS trees
m uint32 // The size of H_MSG() output
securityCategory uint32
sigLen int
pkLen int
}
// sigLen = (1+k*(1+a)+d*(hm+len))*n
var (
SLHDSA128SmallSHA2 = params{alg: "SLH-DSA-SHA2-128s", isShake: 0, isSM3: 0, n: 16, len: 35, h: 63, d: 7, hm: 9, a: 12, k: 14, m: 30,
securityCategory: 1, sigLen: 7856, pkLen: 32}
SLHDSA128SmallSM3 = params{alg: "SLH-DSA-SM3-128s", isShake: 0, isSM3: 1, n: 16, len: 35, h: 63, d: 7, hm: 9, a: 12, k: 14, m: 30,
securityCategory: 1, sigLen: 7856, pkLen: 32}
SLHDSA128SmallSHAKE = params{alg: "SLH-DSA-SHAKE-128s", isShake: 1, isSM3: 0, n: 16, len: 35, h: 63, d: 7, hm: 9, a: 12, k: 14, m: 30,
securityCategory: 1, sigLen: 7856, pkLen: 32}
SLHDSA128FastSHA2 = params{alg: "SLH-DSA-SHA2-128f", isShake: 0, isSM3: 0, n: 16, len: 35, h: 66, d: 22, hm: 3, a: 6, k: 33, m: 34,
securityCategory: 1, sigLen: 17088, pkLen: 32}
SLHDSA128FastSM3 = params{alg: "SLH-DSA-SM3-128f", isShake: 0, isSM3: 10, n: 16, len: 35, h: 66, d: 22, hm: 3, a: 6, k: 33, m: 34,
securityCategory: 1, sigLen: 17088, pkLen: 32}
SLHDSA128FastSHAKE = params{alg: "SLH-DSA-SHAKE-128f", isShake: 1, isSM3: 0, n: 16, len: 35, h: 66, d: 22, hm: 3, a: 6, k: 33, m: 34,
securityCategory: 1, sigLen: 17088, pkLen: 32}
SLHDSA192SmallSHA2 = params{alg: "SLH-DSA-SHA2-192s", isShake: 0, isSM3: 0, n: 24, len: 51, h: 63, d: 7, hm: 9, a: 14, k: 17, m: 39,
securityCategory: 3, sigLen: 16224, pkLen: 48}
SLHDSA192SmallSHAKE = params{alg: "SLH-DSA-SHAKE-192s", isShake: 1, isSM3: 0, n: 24, len: 51, h: 63, d: 7, hm: 9, a: 14, k: 17, m: 39,
securityCategory: 3, sigLen: 16224, pkLen: 48}
SLHDSA192FastSHA2 = params{alg: "SLH-DSA-SHA2-192f", isShake: 0, isSM3: 0, n: 24, len: 51, h: 66, d: 22, hm: 3, a: 8, k: 33, m: 42,
securityCategory: 3, sigLen: 35664, pkLen: 48}
SLHDSA192FastSHAKE = params{alg: "SLH-DSA-SHAKE-192f", isShake: 1, isSM3: 0, n: 24, len: 51, h: 66, d: 22, hm: 3, a: 8, k: 33, m: 42,
securityCategory: 3, sigLen: 35664, pkLen: 48}
SLHDSA256SmallSHA2 = params{alg: "SLH-DSA-SHA2-256s", isShake: 0, isSM3: 0, n: 32, len: 67, h: 64, d: 8, hm: 8, a: 14, k: 22, m: 47,
securityCategory: 5, sigLen: 29792, pkLen: 64}
SLHDSA256SmallSHAKE = params{alg: "SLH-DSA-SHAKE-256s", isShake: 1, isSM3: 0, n: 32, len: 67, h: 64, d: 8, hm: 8, a: 14, k: 22, m: 47,
securityCategory: 5, sigLen: 29792, pkLen: 64}
SLHDSA256FastSHA2 = params{alg: "SLH-DSA-SHA2-256f", isShake: 0, isSM3: 0, n: 32, len: 67, h: 68, d: 17, hm: 4, a: 9, k: 35, m: 49,
securityCategory: 5, sigLen: 49856, pkLen: 64}
SLHDSA256FastSHAKE = params{alg: "SLH-DSA-SHAKE-256f", isShake: 1, isSM3: 0, n: 32, len: 67, h: 68, d: 17, hm: 4, a: 9, k: 35, m: 49,
securityCategory: 5, sigLen: 49856, pkLen: 64}
)
var parameterSets = map[string]*params{
"SLH-DSA-SHA2-128s": &SLHDSA128SmallSHA2,
"SLH-DSA-SHA2-128f": &SLHDSA128FastSHA2,
"SLH-DSA-SHA2-192s": &SLHDSA192SmallSHA2,
"SLH-DSA-SHA2-192f": &SLHDSA192FastSHA2,
"SLH-DSA-SHA2-256s": &SLHDSA256SmallSHA2,
"SLH-DSA-SHA2-256f": &SLHDSA256FastSHA2,
"SLH-DSA-SM3-128s": &SLHDSA128SmallSM3,
"SLH-DSA-SM3-128f": &SLHDSA128FastSM3,
"SLH-DSA-SHAKE-128s": &SLHDSA128SmallSHAKE,
"SLH-DSA-SHAKE-128f": &SLHDSA128FastSHAKE,
"SLH-DSA-SHAKE-192s": &SLHDSA192SmallSHAKE,
"SLH-DSA-SHAKE-192f": &SLHDSA192FastSHAKE,
"SLH-DSA-SHAKE-256s": &SLHDSA256SmallSHAKE,
"SLH-DSA-SHAKE-256f": &SLHDSA256FastSHAKE,
}
func GetParameterSet(name string) (*params, bool) {
if p, ok := parameterSets[name]; ok {
return p, true
}
return nil, false
}
func (p *params) Equal(x any) bool {
if x == nil {
return false
}
if p2, ok := x.(*params); ok {
return p.alg == p2.alg && p.isShake == p2.isShake && p.isSM3 == p2.isSM3 &&
p.n == p2.n && p.h == p2.h && p.d == p2.d && p.hm == p2.hm &&
p.a == p2.a && p.k == p2.k && p.m == p2.m &&
p.securityCategory == p2.securityCategory &&
p.sigLen == p2.sigLen && p.pkLen == p2.pkLen
}
return false
}
func (p *params) mdLen() int {
return int(p.k*p.a+7) >> 3
}
func (p *params) treeIdxLen() int {
return int(p.h-p.hm+7) >> 3 // 7 or 8 bytes
}
func (p *params) treeIdxMask() uint64 {
return (1 << (p.h - p.hm)) - 1
}
func (p *params) leafIdxLen() int {
return int(p.hm+7) >> 3 // 1 or 2 bytes
}
func (p *params) leafIdxMask() uint64 {
return (1 << p.hm) - 1
}
func (p *params) String() string {
return p.alg
}
// GenerateKey generates a new private key using the provided random source and the parameters
// specified by the receiver.
func (p *params) GenerateKey(rand io.Reader) (*PrivateKey, error) {
return GenerateKey(rand, p)
}
// NewPublicKey creates a new PublicKey instance from the provided byte slice using the current parameter set.
func (p *params) NewPublicKey(bytes []byte) (*PublicKey, error) {
return NewPublicKey(bytes, p)
}
// NewPrivateKey creates a new PrivateKey instance using the provided byte slice and the current parameter set.
func (p *params) NewPrivateKey(bytes []byte) (*PrivateKey, error) {
return NewPrivateKey(bytes, p)
}