Files
go-trustlog/internal/helpers/cbor.go

49 lines
1.7 KiB
Go
Raw Normal View History

package helpers
import (
"fmt"
"sync"
"github.com/fxamacker/cbor/v2"
)
var (
//nolint:gochecknoglobals // 使用 sync.Once 模式需要全局变量来确保单次初始化
canonicalEncModeOnce sync.Once
canonicalEncMode cbor.EncMode //nolint:gochecknoglobals // 使用 sync.Once 模式需要全局变量来确保单次初始化
errCanonicalEncMode error
)
// getCanonicalEncMode 获取 Canonical CBOR 编码模式。
// 使用 Canonical CBOR 编码模式,确保序列化结果的一致性。
// Canonical CBOR 遵循 RFC 7049 Section 3.9,保证相同数据在不同实现间产生相同的字节序列。
// 使用 TimeRFC3339Nano 模式确保 time.Time 的纳秒精度被完整保留。
func getCanonicalEncMode() (cbor.EncMode, error) {
canonicalEncModeOnce.Do(func() {
opts := cbor.CanonicalEncOptions()
// 设置时间编码模式为 RFC3339Nano以保留纳秒精度
opts.Time = cbor.TimeRFC3339Nano
canonicalEncMode, errCanonicalEncMode = opts.EncMode()
if errCanonicalEncMode != nil {
errCanonicalEncMode = fmt.Errorf("failed to create canonical CBOR encoder: %w", errCanonicalEncMode)
}
})
return canonicalEncMode, errCanonicalEncMode
}
// MarshalCanonical 使用 Canonical CBOR 编码序列化数据。
// 确保相同数据在不同实现间产生相同的字节序列,适用于需要确定性序列化的场景。
func MarshalCanonical(v interface{}) ([]byte, error) {
encMode, err := getCanonicalEncMode()
if err != nil {
return nil, err
}
return encMode.Marshal(v)
}
// Unmarshal 反序列化 CBOR 数据。
// 支持标准 CBOR 和 Canonical CBOR 格式。
func Unmarshal(data []byte, v interface{}) error {
return cbor.Unmarshal(data, v)
}