// 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/subtle"

// htSign generates a hypertree signature.
//
// See FIPS 205 Algorithm 12 ht_sign
func (sk *PrivateKey) htSign(pkFors []byte, treeIdx uint64, leafIdx uint32, signature []byte) {
	adrs := sk.addressCreator()

	sigLenPerLayer := (sk.params.hm + sk.params.len) * sk.params.n
	mask := sk.params.leafIdxMask()

	var rootBuf [maxN]byte
	root := rootBuf[:sk.params.n]
	copy(root, pkFors)
	tmpBuf := make([]byte, sk.params.n*sk.params.len)
	for j := range sk.params.d {
		adrs.setLayerAddress(j)
		adrs.setTreeAddress(treeIdx)
		sk.xmssSign(root, tmpBuf, leafIdx, adrs, signature)

		if j < sk.params.d-1 {
			sk.xmssPkFromSig(leafIdx, signature, root, tmpBuf, adrs, root)
			// hm least significant bits of treeIdx
			leafIdx = uint32(treeIdx & mask)
			// remove least significant hm bits from treeIdx
			treeIdx >>= sk.params.hm
			signature = signature[sigLenPerLayer:]
		}
	}
}

// htVerify verifies a hypertree signature.
//
// See FIPS 205 Algorithm 13 ht_verify
func (pk *PublicKey) htVerify(pkFors []byte, signature []byte, treeIdx uint64, leafIdx uint32) bool {
	adrs := pk.addressCreator()

	sigLenPerLayer := (pk.params.hm + pk.params.len) * pk.params.n
	mask := pk.params.leafIdxMask()

	var rootBuf [maxN]byte
	root := rootBuf[:pk.params.n]
	copy(root, pkFors)
	tmpBuf := make([]byte, pk.params.n*pk.params.len)
	for j := range pk.params.d {
		adrs.setLayerAddress(j)
		adrs.setTreeAddress(treeIdx)
		pk.xmssPkFromSig(leafIdx, signature, root, tmpBuf, adrs, root)
		// hm least significant bits of treeIdx
		leafIdx = uint32(treeIdx & mask)
		// remove least significant hm bits from treeIdx
		treeIdx >>= pk.params.hm
		signature = signature[sigLenPerLayer:]
	}
	return subtle.ConstantTimeCompare(pk.root[:pk.params.n], root) == 1
}
