mirror of
https://github.com/emmansun/gmsm.git
synced 2025-09-16 03:43:50 +08:00
![github-actions[bot]](/assets/img/avatar_default.png)
* build(deps): bump github/codeql-action from 3.29.11 to 3.30.0 (#361) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.29.11 to 3.30.0. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](3c3833e0f8...2d92b76c45
) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: 3.30.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump codecov/codecov-action from 5.5.0 to 5.5.1 (#362) Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 5.5.0 to 5.5.1. - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](fdcc847654...5a1091511a
) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-version: 5.5.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump actions/setup-go from 5.5.0 to 6.0.0 (#363) Bumps [actions/setup-go](https://github.com/actions/setup-go) from 5.5.0 to 6.0.0. - [Release notes](https://github.com/actions/setup-go/releases) - [Commits](d35c59abb0...4469467582
) --- updated-dependencies: - dependency-name: actions/setup-go dependency-version: 6.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump github/codeql-action from 3.30.0 to 3.30.1 (#364) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.30.0 to 3.30.1. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](2d92b76c45...f1f6e5f6af
) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: 3.30.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump step-security/harden-runner from 2.13.0 to 2.13.1 (#367) Bumps [step-security/harden-runner](https://github.com/step-security/harden-runner) from 2.13.0 to 2.13.1. - [Release notes](https://github.com/step-security/harden-runner/releases) - [Commits](ec9f2d5744...f4a75cfd61
) --- updated-dependencies: - dependency-name: step-security/harden-runner dependency-version: 2.13.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump github/codeql-action from 3.30.1 to 3.30.2 (#368) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.30.1 to 3.30.2. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](f1f6e5f6af...d3678e237b
) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: 3.30.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * feat(mlkem): initialize mlkem from golang standard library * chore(mlkem): refactoring, reduce alloc times * build(deps): bump github/codeql-action from 3.30.2 to 3.30.3 (#369) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.30.2 to 3.30.3. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](d3678e237b...192325c861
) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: 3.30.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * doc(README): include MLKEM * mldsa: refactor the implementation of key and sign/verify * mldsa,slhdsa: crypto.Signer assertion * fix(slhdsa): GenerateKey slice issue #72 * fix(slhdsa): copy/paste issue --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Sun Yimin <emmansun@users.noreply.github.com>
175 lines
5.4 KiB
Go
175 lines
5.4 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 (
|
|
"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) 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")
|
|
}
|
|
ctxLen := len(context)
|
|
if ctxLen > maxContextLen {
|
|
return nil, errors.New("slhdsa: context too long")
|
|
}
|
|
|
|
var mPrefix [maxContextLen + 2]byte
|
|
|
|
mPrefix[1] = byte(ctxLen)
|
|
if ctxLen > 0 {
|
|
copy(mPrefix[2:], context)
|
|
}
|
|
return sk.signInternal(mPrefix[:2+ctxLen], message, addRand)
|
|
}
|
|
|
|
// See FIPS 205 Algorithm 19 slh_sign_internal
|
|
func (sk *PrivateKey) signInternal(msgPrefix, message, addRand []byte) ([]byte, error) {
|
|
signatureHead := make([]byte, sk.params.sigLen)
|
|
|
|
// generate randomizer
|
|
if len(addRand) == 0 {
|
|
// substitute addRand with sk.PublicKey.seed for the deterministic variant
|
|
addRand = sk.PublicKey.seed[:sk.params.n]
|
|
}
|
|
sk.h.prfMsg(sk, addRand, msgPrefix, message, signatureHead)
|
|
R := signatureHead[:sk.params.n]
|
|
signature := signatureHead[sk.params.n:]
|
|
|
|
// compute message digest
|
|
var digest [maxM]byte
|
|
sk.h.hMsg(&sk.PublicKey, R, msgPrefix, message, digest[:])
|
|
// Grab the first mdLen() bytes of digest to use in fors_sign()
|
|
mdLen := sk.params.mdLen()
|
|
md := digest[:mdLen]
|
|
|
|
// Grab remaining bytes from digest to select tree and leaf id's
|
|
remaining := digest[mdLen:]
|
|
treeIdxLen := sk.params.treeIdxLen()
|
|
leafIdxLen := sk.params.leafIdxLen()
|
|
treeIdx := toInt(remaining[:treeIdxLen]) & sk.params.treeIdxMask()
|
|
remaining = remaining[treeIdxLen:]
|
|
leafIdx := uint32(toInt(remaining[:leafIdxLen]) & sk.params.leafIdxMask())
|
|
|
|
// The address adrs must have the layer address set to zero (since the XMSS tree that signs a FORS key is always at layer 0),
|
|
// the tree address set to the index of the WOTS+ key within the XMSS tree that signs the FORS key.
|
|
adrs := sk.addressCreator()
|
|
adrs.setTreeAddress(treeIdx)
|
|
adrs.setTypeAndClear(AddressTypeFORSTree)
|
|
adrs.setKeyPairAddress(leafIdx)
|
|
// generate the FORS signature and append it to the SLH-DSA signature
|
|
sk.forsSign(md, adrs, signature)
|
|
|
|
var pkFors [maxN]byte
|
|
// calculate the FORS public key using the generated FORS signature
|
|
signature = sk.forsPkFromSig(md, signature, adrs, pkFors[:])
|
|
// generate ht signature and append to the SLH-DSA signature
|
|
sk.htSign(pkFors[:sk.params.n], treeIdx, leafIdx, signature)
|
|
|
|
return signatureHead, nil
|
|
}
|
|
|
|
// Verify verifies a pure SLH-DSA signature for the given message.
|
|
//
|
|
// See FIPS 205 Algorithm 24 slh_verify
|
|
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
|
|
}
|
|
|
|
ctxLen := len(context)
|
|
var msgPrefix [maxContextLen + 2]byte
|
|
msgPrefix[1] = byte(ctxLen)
|
|
if ctxLen > 0 {
|
|
copy(msgPrefix[2:], context)
|
|
}
|
|
return pk.verifyInternal(signature, msgPrefix[:2+ctxLen], message)
|
|
}
|
|
|
|
// See FIPS 205 Algorithm 20 slh_verify_internal
|
|
func (pk *PublicKey) verifyInternal(signature []byte, msgPrefix []byte, message []byte) bool {
|
|
if len(signature) != pk.params.sigLen {
|
|
return false
|
|
}
|
|
adrs := pk.addressCreator()
|
|
R := signature[:pk.params.n]
|
|
signature = signature[pk.params.n:]
|
|
|
|
// compute message digest
|
|
var digest [maxM]byte
|
|
pk.h.hMsg(pk, R, msgPrefix, message, digest[:])
|
|
// Grab the first mdLen() bytes of digest to use in fors_sign()
|
|
mdLen := pk.params.mdLen()
|
|
md := digest[:mdLen]
|
|
|
|
// Grab remaining bytes from digest to select tree and leaf id's
|
|
remaining := digest[mdLen:]
|
|
treeIdxLen := pk.params.treeIdxLen()
|
|
leafIdxLen := pk.params.leafIdxLen()
|
|
treeIdx := toInt(remaining[:treeIdxLen]) & pk.params.treeIdxMask()
|
|
remaining = remaining[treeIdxLen:]
|
|
leafIdx := uint32(toInt(remaining[:leafIdxLen]) & pk.params.leafIdxMask())
|
|
|
|
adrs.setTreeAddress(treeIdx)
|
|
adrs.setTypeAndClear(AddressTypeFORSTree)
|
|
adrs.setKeyPairAddress(leafIdx)
|
|
|
|
var pkFors [maxN]byte
|
|
// calculate the FORS public key using the given FORS signature
|
|
signature = pk.forsPkFromSig(md, signature, adrs, pkFors[:])
|
|
|
|
return pk.htVerify(pkFors[:pk.params.n], signature, treeIdx, leafIdx)
|
|
}
|
|
|
|
func toInt(b []byte) uint64 {
|
|
var ret uint64
|
|
for i := range b {
|
|
ret = ret<<8 + uint64(b[i])
|
|
}
|
|
return ret
|
|
}
|