Fiat-Shamir hashes need to say which execution context they belong to, and they
need an injective encoding of the transcript values. Pre-fix tss-lib was
missing both: proof challenges had no caller-supplied session/context tag, and
individual inputs were concatenated without recording their lengths.
Before v2.0.0, bnb-chain/tss-lib used a shared SHA512_256i helper for proof
challenges across Schnorr, MtA, DLN, and commitment proofs. The helper included
a block-count prefix, but no caller-supplied session/context tag and no
per-input length tag (source).
The fix (PR #256) introduced
SHA512_256i_TAGGED. The tag is supplied by the caller and is typically a
session or party/session context, not a universal proof-type tag; separation
between proof types also depends on the different statement inputs each proof
hashes. The helper hashes the tag into the state and records each input length
before hashing the transcript (source):
1// FILE: common/hash.go - bnb-chain/tss-lib v2.0.0 (fixed excerpt)
2func SHA512_256i_TAGGED(tag []byte, in ...*big.Int) *big.Int {
3 tagBz := SHA512_256(tag)
4 var data []byte
5 state := crypto.SHA512_256.New()
6 state.Write(tagBz)
7 state.Write(tagBz)
8
9 inLen := len(in)
10 inLenBz := make([]byte, 64/8)
11 binary.LittleEndian.PutUint64(inLenBz, uint64(inLen))
12 ptrs := make([][]byte, inLen)
13 for i, n := range in {
14 ptrs[i] = n.Bytes()
15 }
16 data = append(data, inLenBz...)
17
18 for i := range in {
19 data = append(data, ptrs[i]...)
20 data = append(data, hashInputDelimiter)
21 dataLen := make([]byte, 8)
22 binary.LittleEndian.PutUint64(dataLen, uint64(len(ptrs[i])))
23 data = append(data, dataLen...)
24 }
25
26 state.Write(data)
27 return new(big.Int).SetBytes(state.Sum(nil))
28}