This commit replaces every instance of interface{} with any,
so go1.18 or newer is required to to build.
1023 lines
43 KiB
Go
1023 lines
43 KiB
Go
// Copyright (c) Faye Amacker. All rights reserved.
|
|
// Licensed under the MIT License. See LICENSE in the project root for license information.
|
|
|
|
package cbor
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"reflect"
|
|
"testing"
|
|
)
|
|
|
|
const rounds = 100
|
|
|
|
type claims struct {
|
|
Iss string `cbor:"1,keyasint"`
|
|
Sub string `cbor:"2,keyasint"`
|
|
Aud string `cbor:"3,keyasint"`
|
|
Exp int `cbor:"4,keyasint"`
|
|
Nbf int `cbor:"5,keyasint"`
|
|
Iat int `cbor:"6,keyasint"`
|
|
Cti []byte `cbor:"7,keyasint"`
|
|
}
|
|
|
|
type coseHeader struct {
|
|
Alg int `cbor:"1,keyasint,omitempty"`
|
|
Kid []byte `cbor:"4,keyasint,omitempty"`
|
|
IV []byte `cbor:"5,keyasint,omitempty"`
|
|
}
|
|
|
|
type macedCOSE struct {
|
|
_ struct{} `cbor:",toarray"`
|
|
Protected []byte
|
|
Unprotected coseHeader
|
|
Payload []byte
|
|
Tag []byte
|
|
}
|
|
|
|
type coseKey struct {
|
|
Kty int `cbor:"1,keyasint,omitempty"`
|
|
Kid []byte `cbor:"2,keyasint,omitempty"`
|
|
Alg int `cbor:"3,keyasint,omitempty"`
|
|
KeyOpts int `cbor:"4,keyasint,omitempty"`
|
|
IV []byte `cbor:"5,keyasint,omitempty"`
|
|
CrvOrNOrK RawMessage `cbor:"-1,keyasint,omitempty"` // K for symmetric keys, Crv for elliptic curve keys, N for RSA modulus
|
|
XOrE RawMessage `cbor:"-2,keyasint,omitempty"` // X for curve x-coordinate, E for RSA public exponent
|
|
Y RawMessage `cbor:"-3,keyasint,omitempty"` // Y for curve y-cooridate
|
|
D []byte `cbor:"-4,keyasint,omitempty"`
|
|
}
|
|
|
|
type attestationObject struct {
|
|
AuthnData []byte `cbor:"authData"`
|
|
Fmt string `cbor:"fmt"`
|
|
AttStmt RawMessage `cbor:"attStmt"`
|
|
}
|
|
|
|
type SenMLRecord struct {
|
|
BaseName string `cbor:"-2,keyasint,omitempty"`
|
|
BaseTime float64 `cbor:"-3,keyasint,omitempty"`
|
|
BaseUnit string `cbor:"-4,keyasint,omitempty"`
|
|
BaseValue float64 `cbor:"-5,keyasint,omitempty"`
|
|
BaseSum float64 `cbor:"-6,keyasint,omitempty"`
|
|
BaseVersion int `cbor:"-1,keyasint,omitempty"`
|
|
Name string `cbor:"0,keyasint,omitempty"`
|
|
Unit string `cbor:"1,keyasint,omitempty"`
|
|
Time float64 `cbor:"6,keyasint,omitempty"`
|
|
UpdateTime float64 `cbor:"7,keyasint,omitempty"`
|
|
Value float64 `cbor:"2,keyasint,omitempty"`
|
|
ValueS string `cbor:"3,keyasint,omitempty"`
|
|
ValueB bool `cbor:"4,keyasint,omitempty"`
|
|
ValueD string `cbor:"8,keyasint,omitempty"`
|
|
Sum float64 `cbor:"5,keyasint,omitempty"`
|
|
}
|
|
|
|
type T1 struct {
|
|
T bool
|
|
UI uint
|
|
I int
|
|
F float64
|
|
B []byte
|
|
S string
|
|
Slci []int
|
|
Mss map[string]string
|
|
}
|
|
|
|
type T2 struct {
|
|
T bool `cbor:"1,keyasint"`
|
|
UI uint `cbor:"2,keyasint"`
|
|
I int `cbor:"3,keyasint"`
|
|
F float64 `cbor:"4,keyasint"`
|
|
B []byte `cbor:"5,keyasint"`
|
|
S string `cbor:"6,keyasint"`
|
|
Slci []int `cbor:"7,keyasint"`
|
|
Mss map[string]string `cbor:"8,keyasint"`
|
|
}
|
|
|
|
type T3 struct {
|
|
_ struct{} `cbor:",toarray"`
|
|
T bool
|
|
UI uint
|
|
I int
|
|
F float64
|
|
B []byte
|
|
S string
|
|
Slci []int
|
|
Mss map[string]string
|
|
}
|
|
|
|
type ManyFieldsOneOmitEmpty struct {
|
|
F01, F02, F03, F04, F05, F06, F07, F08, F09, F10, F11, F12, F13, F14, F15, F16 int
|
|
F17, F18, F19, F20, F21, F22, F23, F24, F25, F26, F27, F28, F29, F30, F31 int
|
|
|
|
F32 int `cbor:",omitempty"`
|
|
}
|
|
|
|
type SomeFieldsOneOmitEmpty struct {
|
|
F01, F02, F03, F04, F05, F06, F07 int
|
|
|
|
F08 int `cbor:",omitempty"`
|
|
}
|
|
|
|
type ManyFieldsAllOmitEmpty struct {
|
|
F01 int `cbor:",omitempty"`
|
|
F02 int `cbor:",omitempty"`
|
|
F03 int `cbor:",omitempty"`
|
|
F04 int `cbor:",omitempty"`
|
|
F05 int `cbor:",omitempty"`
|
|
F06 int `cbor:",omitempty"`
|
|
F07 int `cbor:",omitempty"`
|
|
F08 int `cbor:",omitempty"`
|
|
F09 int `cbor:",omitempty"`
|
|
F10 int `cbor:",omitempty"`
|
|
F11 int `cbor:",omitempty"`
|
|
F12 int `cbor:",omitempty"`
|
|
F13 int `cbor:",omitempty"`
|
|
F14 int `cbor:",omitempty"`
|
|
F15 int `cbor:",omitempty"`
|
|
F16 int `cbor:",omitempty"`
|
|
F17 int `cbor:",omitempty"`
|
|
F18 int `cbor:",omitempty"`
|
|
F19 int `cbor:",omitempty"`
|
|
F20 int `cbor:",omitempty"`
|
|
F21 int `cbor:",omitempty"`
|
|
F22 int `cbor:",omitempty"`
|
|
F23 int `cbor:",omitempty"`
|
|
F24 int `cbor:",omitempty"`
|
|
F25 int `cbor:",omitempty"`
|
|
F26 int `cbor:",omitempty"`
|
|
F27 int `cbor:",omitempty"`
|
|
F28 int `cbor:",omitempty"`
|
|
F29 int `cbor:",omitempty"`
|
|
F30 int `cbor:",omitempty"`
|
|
F31 int `cbor:",omitempty"`
|
|
F32 int `cbor:",omitempty"`
|
|
}
|
|
|
|
type SomeFieldsAllOmitEmpty struct {
|
|
F01 int `cbor:",omitempty"`
|
|
F02 int `cbor:",omitempty"`
|
|
F03 int `cbor:",omitempty"`
|
|
F04 int `cbor:",omitempty"`
|
|
F05 int `cbor:",omitempty"`
|
|
F06 int `cbor:",omitempty"`
|
|
F07 int `cbor:",omitempty"`
|
|
F08 int `cbor:",omitempty"`
|
|
}
|
|
|
|
var decodeBenchmarks = []struct {
|
|
name string
|
|
data []byte
|
|
decodeToTypes []reflect.Type
|
|
}{
|
|
{"bool", hexDecode("f5"), []reflect.Type{typeIntf, typeBool}}, // true
|
|
{"positive int", hexDecode("1bffffffffffffffff"), []reflect.Type{typeIntf, typeUint64}}, // uint64(18446744073709551615)
|
|
{"negative int", hexDecode("3903e7"), []reflect.Type{typeIntf, typeInt64}}, // int64(-1000)
|
|
{"float", hexDecode("fbc010666666666666"), []reflect.Type{typeIntf, typeFloat64}}, // float64(-4.1)
|
|
{"bytes", hexDecode("581a0102030405060708090a0b0c0d0e0f101112131415161718191a"), []reflect.Type{typeIntf, typeByteSlice}}, // []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26}
|
|
{"bytes indef len", hexDecode("5f410141024103410441054106410741084109410a410b410c410d410e410f4110411141124113411441154116411741184119411aff"), []reflect.Type{typeIntf, typeByteSlice}}, // []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26}
|
|
{"text", hexDecode("782b54686520717569636b2062726f776e20666f78206a756d7073206f76657220746865206c617a7920646f67"), []reflect.Type{typeIntf, typeString}}, // "The quick brown fox jumps over the lazy dog"
|
|
{"text indef len", hexDecode("7f61546168616561206171617561696163616b612061626172616f6177616e61206166616f61786120616a6175616d617061736120616f61766165617261206174616861656120616c6161617a617961206164616f6167ff"), []reflect.Type{typeIntf, typeString}}, // "The quick brown fox jumps over the lazy dog"
|
|
{"array", hexDecode("981a0102030405060708090a0b0c0d0e0f101112131415161718181819181a"), []reflect.Type{typeIntf, typeIntSlice}}, // []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26}
|
|
{"array indef len", hexDecode("9f0102030405060708090a0b0c0d0e0f101112131415161718181819181aff"), []reflect.Type{typeIntf, typeIntSlice}}, // []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26}
|
|
{"map", hexDecode("ad616161416162614261636143616461446165614561666146616761476168614861696149616a614a616c614c616d614d616e614e"), []reflect.Type{typeIntf, typeMapStringIntf, typeMapStringString}}, // map[string]string{"a": "A", "b": "B", "c": "C", "d": "D", "e": "E", "f": "F", "g": "G", "h": "H", "i": "I", "j": "J", "l": "L", "m": "M", "n": "N"}}
|
|
{"map indef len", hexDecode("bf616161416162614261636143616461446165614561666146616761476168614861696149616a614a616b614b616c614c616d614d616e614eff"), []reflect.Type{typeIntf, typeMapStringIntf, typeMapStringString}}, // map[string]string{"a": "A", "b": "B", "c": "C", "d": "D", "e": "E", "f": "F", "g": "G", "h": "H", "i": "I", "j": "J", "l": "L", "m": "M", "n": "N"}}
|
|
}
|
|
|
|
var encodeBenchmarks = []struct {
|
|
name string
|
|
data []byte
|
|
values []any
|
|
}{
|
|
{"bool", hexDecode("f5"), []any{true}},
|
|
{"positive int", hexDecode("1bffffffffffffffff"), []any{uint64(18446744073709551615)}},
|
|
{"negative int", hexDecode("3903e7"), []any{int64(-1000)}},
|
|
{"float", hexDecode("fbc010666666666666"), []any{float64(-4.1)}},
|
|
{"bytes", hexDecode("581a0102030405060708090a0b0c0d0e0f101112131415161718191a"), []any{[]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26}}},
|
|
{"text", hexDecode("782b54686520717569636b2062726f776e20666f78206a756d7073206f76657220746865206c617a7920646f67"), []any{"The quick brown fox jumps over the lazy dog"}},
|
|
{"array", hexDecode("981a0102030405060708090a0b0c0d0e0f101112131415161718181819181a"), []any{[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26}}},
|
|
{"map", hexDecode("ad616161416162614261636143616461446165614561666146616761476168614861696149616a614a616c614c616d614d616e614e"), []any{map[string]string{"a": "A", "b": "B", "c": "C", "d": "D", "e": "E", "f": "F", "g": "G", "h": "H", "i": "I", "j": "J", "l": "L", "m": "M", "n": "N"}}},
|
|
}
|
|
|
|
func BenchmarkUnmarshal(b *testing.B) {
|
|
for _, bm := range decodeBenchmarks {
|
|
for _, t := range bm.decodeToTypes {
|
|
name := "CBOR " + bm.name + " to Go " + t.String()
|
|
if t.Kind() == reflect.Struct {
|
|
name = "CBOR " + bm.name + " to Go " + t.Kind().String()
|
|
}
|
|
b.Run(name, func(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
vPtr := reflect.New(t).Interface()
|
|
if err := Unmarshal(bm.data, vPtr); err != nil {
|
|
b.Fatal("Unmarshal:", err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
var moreBenchmarks = []struct {
|
|
name string
|
|
data []byte
|
|
decodeToType reflect.Type
|
|
}{
|
|
// Unmarshal CBOR map with string key to map[string]interface{}.
|
|
{
|
|
"CBOR map to Go map[string]interface{}",
|
|
hexDecode("a86154f56255691bffffffffffffffff61493903e76146fbc0106666666666666142581a0102030405060708090a0b0c0d0e0f101112131415161718191a6153782b54686520717569636b2062726f776e20666f78206a756d7073206f76657220746865206c617a7920646f6764536c6369981a0102030405060708090a0b0c0d0e0f101112131415161718181819181a634d7373ad6163614361656145616661466167614761686148616e614e616d614d61616141616261426164614461696149616a614a616c614c"),
|
|
reflect.TypeOf(map[string]any{}),
|
|
},
|
|
// Unmarshal CBOR map with string key to struct.
|
|
{
|
|
"CBOR map to Go struct",
|
|
hexDecode("a86154f56255491bffffffffffffffff61493903e76146fbc0106666666666666142581a0102030405060708090a0b0c0d0e0f101112131415161718191a6153782b54686520717569636b2062726f776e20666f78206a756d7073206f76657220746865206c617a7920646f6764536c6369981a0102030405060708090a0b0c0d0e0f101112131415161718181819181a634d7373ad6163614361656145616661466167614761686148616e614e616d614d61616141616261426164614461696149616a614a616c614c"),
|
|
reflect.TypeOf(T1{}),
|
|
},
|
|
// Unmarshal CBOR map with integer key, such as COSE Key and SenML, to map[int]interface{}.
|
|
{
|
|
"CBOR map to Go map[int]interface{}",
|
|
hexDecode("a801f5021bffffffffffffffff033903e704fbc01066666666666605581a0102030405060708090a0b0c0d0e0f101112131415161718191a06782b54686520717569636b2062726f776e20666f78206a756d7073206f76657220746865206c617a7920646f6707981a0102030405060708090a0b0c0d0e0f101112131415161718181819181a08ad61646144616661466167614761686148616d614d616e614e6161614161626142616361436165614561696149616a614a616c614c"),
|
|
reflect.TypeOf(map[int]any{}),
|
|
},
|
|
// Unmarshal CBOR map with integer key, such as COSE Key and SenML, to struct.
|
|
{
|
|
"CBOR map to Go struct keyasint",
|
|
hexDecode("a801f5021bffffffffffffffff033903e704fbc01066666666666605581a0102030405060708090a0b0c0d0e0f101112131415161718191a06782b54686520717569636b2062726f776e20666f78206a756d7073206f76657220746865206c617a7920646f6707981a0102030405060708090a0b0c0d0e0f101112131415161718181819181a08ad61646144616661466167614761686148616d614d616e614e6161614161626142616361436165614561696149616a614a616c614c"),
|
|
reflect.TypeOf(T2{}),
|
|
},
|
|
// Unmarshal CBOR array of known sequence of data types, such as signed/maced/encrypted CWT, to []interface{}.
|
|
{
|
|
"CBOR array to Go []interface{}",
|
|
hexDecode("88f51bffffffffffffffff3903e7fbc010666666666666581a0102030405060708090a0b0c0d0e0f101112131415161718191a782b54686520717569636b2062726f776e20666f78206a756d7073206f76657220746865206c617a7920646f67981a0102030405060708090a0b0c0d0e0f101112131415161718181819181aad616261426163614361646144616561456166614661696149616e614e616161416167614761686148616a614a616c614c616d614d"),
|
|
reflect.TypeOf([]any{}),
|
|
},
|
|
// Unmarshal CBOR array of known sequence of data types, such as signed/maced/encrypted CWT, to struct.
|
|
{
|
|
"CBOR array to Go struct toarray",
|
|
hexDecode("88f51bffffffffffffffff3903e7fbc010666666666666581a0102030405060708090a0b0c0d0e0f101112131415161718191a782b54686520717569636b2062726f776e20666f78206a756d7073206f76657220746865206c617a7920646f67981a0102030405060708090a0b0c0d0e0f101112131415161718181819181aad616261426163614361646144616561456166614661696149616e614e616161416167614761686148616a614a616c614c616d614d"),
|
|
reflect.TypeOf(T3{}),
|
|
},
|
|
}
|
|
for _, bm := range moreBenchmarks {
|
|
b.Run(bm.name, func(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
vPtr := reflect.New(bm.decodeToType).Interface()
|
|
if err := Unmarshal(bm.data, vPtr); err != nil {
|
|
b.Fatal("Unmarshal:", err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func BenchmarkUnmarshalFirst(b *testing.B) {
|
|
// Random trailing data
|
|
trailingData := hexDecode("4a6b0f4718c73f391091ea1c")
|
|
for _, bm := range decodeBenchmarks {
|
|
for _, t := range bm.decodeToTypes {
|
|
name := "CBOR " + bm.name + " to Go " + t.String()
|
|
if t.Kind() == reflect.Struct {
|
|
name = "CBOR " + bm.name + " to Go " + t.Kind().String()
|
|
}
|
|
data := make([]byte, 0, len(bm.data)+len(trailingData))
|
|
data = append(data, bm.data...)
|
|
data = append(data, trailingData...)
|
|
b.Run(name, func(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
vPtr := reflect.New(t).Interface()
|
|
if _, err := UnmarshalFirst(data, vPtr); err != nil {
|
|
b.Fatal("UnmarshalFirst:", err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkUnmarshalFirstViaDecoder(b *testing.B) {
|
|
// Random trailing data
|
|
trailingData := hexDecode("4a6b0f4718c73f391091ea1c")
|
|
for _, bm := range decodeBenchmarks {
|
|
for _, t := range bm.decodeToTypes {
|
|
name := "CBOR " + bm.name + " to Go " + t.String()
|
|
if t.Kind() == reflect.Struct {
|
|
name = "CBOR " + bm.name + " to Go " + t.Kind().String()
|
|
}
|
|
data := make([]byte, 0, len(bm.data)+len(trailingData))
|
|
data = append(data, bm.data...)
|
|
data = append(data, trailingData...)
|
|
b.Run(name, func(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
vPtr := reflect.New(t).Interface()
|
|
if err := NewDecoder(bytes.NewReader(data)).Decode(vPtr); err != nil {
|
|
b.Fatal("UnmarshalDecoder:", err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkDecode(b *testing.B) {
|
|
for _, bm := range decodeBenchmarks {
|
|
for _, t := range bm.decodeToTypes {
|
|
name := "CBOR " + bm.name + " to Go " + t.String()
|
|
if t.Kind() == reflect.Struct {
|
|
name = "CBOR " + bm.name + " to Go " + t.Kind().String()
|
|
}
|
|
buf := bytes.NewReader(bm.data)
|
|
decoder := NewDecoder(buf)
|
|
b.Run(name, func(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
vPtr := reflect.New(t).Interface()
|
|
if err := decoder.Decode(vPtr); err != nil {
|
|
b.Fatal("Decode:", err)
|
|
}
|
|
buf.Seek(0, 0) //nolint:errcheck
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkDecodeStream(b *testing.B) {
|
|
var data []byte
|
|
for _, bm := range decodeBenchmarks {
|
|
for i := 0; i < len(bm.decodeToTypes); i++ {
|
|
data = append(data, bm.data...)
|
|
}
|
|
}
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
buf := bytes.NewReader(data)
|
|
decoder := NewDecoder(buf)
|
|
for j := 0; j < rounds; j++ {
|
|
for _, bm := range decodeBenchmarks {
|
|
for _, t := range bm.decodeToTypes {
|
|
vPtr := reflect.New(t).Interface()
|
|
if err := decoder.Decode(vPtr); err != nil {
|
|
b.Fatal("Decode:", err)
|
|
}
|
|
}
|
|
}
|
|
buf.Seek(0, 0) //nolint:errcheck
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkMarshal(b *testing.B) {
|
|
for _, bm := range encodeBenchmarks {
|
|
for _, v := range bm.values {
|
|
name := "Go " + reflect.TypeOf(v).String() + " to CBOR " + bm.name
|
|
if reflect.TypeOf(v).Kind() == reflect.Struct {
|
|
name = "Go " + reflect.TypeOf(v).Kind().String() + " to CBOR " + bm.name
|
|
}
|
|
b.Run(name, func(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
if _, err := Marshal(v); err != nil {
|
|
b.Fatal("Marshal:", err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
// Marshal map[string]interface{} to CBOR map
|
|
m1 := map[string]any{
|
|
"T": true,
|
|
"UI": uint(18446744073709551615),
|
|
"I": -1000,
|
|
"F": -4.1,
|
|
"B": []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26},
|
|
"S": "The quick brown fox jumps over the lazy dog",
|
|
"Slci": []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26},
|
|
"Mss": map[string]string{"a": "A", "b": "B", "c": "C", "d": "D", "e": "E", "f": "F", "g": "G", "h": "H", "i": "I", "j": "J", "l": "L", "m": "M", "n": "N"},
|
|
}
|
|
// Marshal struct to CBOR map
|
|
v1 := T1{ //nolint:dupl
|
|
T: true,
|
|
UI: 18446744073709551615,
|
|
I: -1000,
|
|
F: -4.1,
|
|
B: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26},
|
|
S: "The quick brown fox jumps over the lazy dog",
|
|
Slci: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26},
|
|
Mss: map[string]string{"a": "A", "b": "B", "c": "C", "d": "D", "e": "E", "f": "F", "g": "G", "h": "H", "i": "I", "j": "J", "l": "L", "m": "M", "n": "N"},
|
|
}
|
|
// Marshal map[int]interface{} to CBOR map
|
|
m2 := map[int]any{
|
|
1: true,
|
|
2: uint(18446744073709551615),
|
|
3: -1000,
|
|
4: -4.1,
|
|
5: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26},
|
|
6: "The quick brown fox jumps over the lazy dog",
|
|
7: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26},
|
|
8: map[string]string{"a": "A", "b": "B", "c": "C", "d": "D", "e": "E", "f": "F", "g": "G", "h": "H", "i": "I", "j": "J", "l": "L", "m": "M", "n": "N"},
|
|
}
|
|
// Marshal struct keyasint, such as COSE Key and SenML
|
|
v2 := T2{ //nolint:dupl
|
|
T: true,
|
|
UI: 18446744073709551615,
|
|
I: -1000,
|
|
F: -4.1,
|
|
B: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26},
|
|
S: "The quick brown fox jumps over the lazy dog",
|
|
Slci: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26},
|
|
Mss: map[string]string{"a": "A", "b": "B", "c": "C", "d": "D", "e": "E", "f": "F", "g": "G", "h": "H", "i": "I", "j": "J", "l": "L", "m": "M", "n": "N"},
|
|
}
|
|
// Marshal []interface to CBOR array.
|
|
slc := []any{
|
|
true,
|
|
uint(18446744073709551615),
|
|
-1000,
|
|
-4.1,
|
|
[]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26},
|
|
"The quick brown fox jumps over the lazy dog",
|
|
[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26},
|
|
map[string]string{"a": "A", "b": "B", "c": "C", "d": "D", "e": "E", "f": "F", "g": "G", "h": "H", "i": "I", "j": "J", "l": "L", "m": "M", "n": "N"},
|
|
}
|
|
// Marshal struct toarray to CBOR array, such as signed/maced/encrypted CWT.
|
|
v3 := T3{ //nolint:dupl
|
|
T: true,
|
|
UI: 18446744073709551615,
|
|
I: -1000,
|
|
F: -4.1,
|
|
B: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26},
|
|
S: "The quick brown fox jumps over the lazy dog",
|
|
Slci: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26},
|
|
Mss: map[string]string{"a": "A", "b": "B", "c": "C", "d": "D", "e": "E", "f": "F", "g": "G", "h": "H", "i": "I", "j": "J", "l": "L", "m": "M", "n": "N"},
|
|
}
|
|
var moreBenchmarks = []struct {
|
|
name string
|
|
value any
|
|
}{
|
|
{"Go map[string]interface{} to CBOR map", m1},
|
|
{"Go struct to CBOR map", v1},
|
|
{"Go struct many fields all omitempty all empty to CBOR map", ManyFieldsAllOmitEmpty{}},
|
|
{"Go struct some fields all omitempty all empty to CBOR map", SomeFieldsAllOmitEmpty{}},
|
|
{"Go struct many fields all omitempty all nonempty to CBOR map", ManyFieldsAllOmitEmpty{
|
|
F01: 1, F02: 1, F03: 1, F04: 1, F05: 1, F06: 1, F07: 1, F08: 1, F09: 1, F10: 1, F11: 1, F12: 1, F13: 1, F14: 1, F15: 1, F16: 1,
|
|
F17: 1, F18: 1, F19: 1, F20: 1, F21: 1, F22: 1, F23: 1, F24: 1, F25: 1, F26: 1, F27: 1, F28: 1, F29: 1, F30: 1, F31: 1, F32: 1,
|
|
}},
|
|
{"Go struct some fields all omitempty all nonempty to CBOR map", SomeFieldsAllOmitEmpty{
|
|
F01: 1, F02: 1, F03: 1, F04: 1, F05: 1, F06: 1, F07: 1, F08: 1,
|
|
}},
|
|
{"Go struct many fields one omitempty to CBOR map", ManyFieldsOneOmitEmpty{}},
|
|
{"Go struct some fields one omitempty to CBOR map", SomeFieldsOneOmitEmpty{}},
|
|
{"Go map[int]interface{} to CBOR map", m2},
|
|
{"Go struct keyasint to CBOR map", v2},
|
|
{"Go []interface{} to CBOR map", slc},
|
|
{"Go struct toarray to CBOR array", v3},
|
|
}
|
|
for _, bm := range moreBenchmarks {
|
|
b.Run(bm.name, func(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
if _, err := Marshal(bm.value); err != nil {
|
|
b.Fatal("Marshal:", err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func BenchmarkMarshalCanonical(b *testing.B) {
|
|
type strc struct {
|
|
A string `cbor:"a"`
|
|
B string `cbor:"b"`
|
|
C string `cbor:"c"`
|
|
D string `cbor:"d"`
|
|
E string `cbor:"e"`
|
|
F string `cbor:"f"`
|
|
G string `cbor:"g"`
|
|
H string `cbor:"h"`
|
|
I string `cbor:"i"`
|
|
J string `cbor:"j"`
|
|
L string `cbor:"l"`
|
|
M string `cbor:"m"`
|
|
N string `cbor:"n"`
|
|
}
|
|
for _, bm := range []struct {
|
|
name string
|
|
data []byte
|
|
values []any
|
|
}{
|
|
{"map", hexDecode("ad616161416162614261636143616461446165614561666146616761476168614861696149616a614a616c614c616d614d616e614e"), []any{map[string]string{"a": "A", "b": "B", "c": "C", "d": "D", "e": "E", "f": "F", "g": "G", "h": "H", "i": "I", "j": "J", "l": "L", "m": "M", "n": "N"}, strc{A: "A", B: "B", C: "C", D: "D", E: "E", F: "F", G: "G", H: "H", I: "I", J: "J", L: "L", M: "M", N: "N"}, map[int]int{0: 0} /* single-entry map */}},
|
|
} {
|
|
for _, v := range bm.values {
|
|
name := "Go " + reflect.TypeOf(v).String() + " to CBOR " + bm.name
|
|
if reflect.TypeOf(v).Kind() == reflect.Struct {
|
|
name = "Go " + reflect.TypeOf(v).Kind().String() + " to CBOR " + bm.name
|
|
}
|
|
b.Run(name, func(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
if _, err := Marshal(v); err != nil {
|
|
b.Fatal("Marshal:", err)
|
|
}
|
|
}
|
|
})
|
|
// Canonical encoding
|
|
name = "Go " + reflect.TypeOf(v).String() + " to CBOR " + bm.name + " canonical"
|
|
if reflect.TypeOf(v).Kind() == reflect.Struct {
|
|
name = "Go " + reflect.TypeOf(v).Kind().String() + " to CBOR " + bm.name + " canonical"
|
|
}
|
|
em, _ := EncOptions{Sort: SortCanonical}.EncMode()
|
|
b.Run(name, func(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
if _, err := em.Marshal(v); err != nil {
|
|
b.Fatal("Marshal:", err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
// BenchmarkNewEncoderEncode benchmarks NewEncoder() and Encode().
|
|
func BenchmarkNewEncoderEncode(b *testing.B) {
|
|
for _, bm := range encodeBenchmarks {
|
|
for _, v := range bm.values {
|
|
name := "Go " + reflect.TypeOf(v).String() + " to CBOR " + bm.name
|
|
if reflect.TypeOf(v).Kind() == reflect.Struct {
|
|
name = "Go " + reflect.TypeOf(v).Kind().String() + " to CBOR " + bm.name
|
|
}
|
|
b.Run(name, func(b *testing.B) {
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
encoder := NewEncoder(io.Discard)
|
|
if err := encoder.Encode(v); err != nil {
|
|
b.Fatal("Encode:", err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
// BenchmarkEncode benchmarks Encode(). It reuses same Encoder to exclude NewEncoder()
|
|
// from the benchmark.
|
|
func BenchmarkEncode(b *testing.B) {
|
|
for _, bm := range encodeBenchmarks {
|
|
for _, v := range bm.values {
|
|
name := "Go " + reflect.TypeOf(v).String() + " to CBOR " + bm.name
|
|
if reflect.TypeOf(v).Kind() == reflect.Struct {
|
|
name = "Go " + reflect.TypeOf(v).Kind().String() + " to CBOR " + bm.name
|
|
}
|
|
b.Run(name, func(b *testing.B) {
|
|
encoder := NewEncoder(io.Discard)
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
if err := encoder.Encode(v); err != nil {
|
|
b.Fatal("Encode:", err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkEncodeStream(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
encoder := NewEncoder(io.Discard)
|
|
for i := 0; i < rounds; i++ {
|
|
for _, bm := range encodeBenchmarks {
|
|
for _, v := range bm.values {
|
|
if err := encoder.Encode(v); err != nil {
|
|
b.Fatal("Encode:", err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkUnmarshalCOSE(b *testing.B) {
|
|
// Data from https://tools.ietf.org/html/rfc8392#appendix-A section A.2
|
|
testCases := []struct {
|
|
name string
|
|
data []byte
|
|
}{
|
|
{"128-Bit Symmetric Key", hexDecode("a42050231f4c4d4d3051fdc2ec0a3851d5b3830104024c53796d6d6574726963313238030a")},
|
|
{"256-Bit Symmetric Key", hexDecode("a4205820403697de87af64611c1d32a05dab0fe1fcb715a86ab435f1ec99192d795693880104024c53796d6d6574726963323536030a")},
|
|
{"ECDSA P256 256-Bit Key", hexDecode("a72358206c1382765aec5358f117733d281c1c7bdc39884d04a45a1e6c67c858bc206c1922582060f7f1a780d8a783bfb7a2dd6b2796e8128dbbcef9d3d168db9529971a36e7b9215820143329cce7868e416927599cf65a34f3ce2ffda55a7eca69ed8919a394d42f0f2001010202524173796d6d657472696345434453413235360326")},
|
|
}
|
|
for _, tc := range testCases {
|
|
b.Run(tc.name, func(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
var v coseKey
|
|
if err := Unmarshal(tc.data, &v); err != nil {
|
|
b.Fatal("Unmarshal:", err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func BenchmarkMarshalCOSE(b *testing.B) {
|
|
// Data from https://tools.ietf.org/html/rfc8392#appendix-A section A.2
|
|
testCases := []struct {
|
|
name string
|
|
data []byte
|
|
}{
|
|
{"128-Bit Symmetric Key", hexDecode("a42050231f4c4d4d3051fdc2ec0a3851d5b3830104024c53796d6d6574726963313238030a")},
|
|
{"256-Bit Symmetric Key", hexDecode("a4205820403697de87af64611c1d32a05dab0fe1fcb715a86ab435f1ec99192d795693880104024c53796d6d6574726963323536030a")},
|
|
{"ECDSA P256 256-Bit Key", hexDecode("a72358206c1382765aec5358f117733d281c1c7bdc39884d04a45a1e6c67c858bc206c1922582060f7f1a780d8a783bfb7a2dd6b2796e8128dbbcef9d3d168db9529971a36e7b9215820143329cce7868e416927599cf65a34f3ce2ffda55a7eca69ed8919a394d42f0f2001010202524173796d6d657472696345434453413235360326")},
|
|
}
|
|
for _, tc := range testCases {
|
|
var v coseKey
|
|
if err := Unmarshal(tc.data, &v); err != nil {
|
|
b.Fatal("Unmarshal:", err)
|
|
}
|
|
b.Run(tc.name, func(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
if _, err := Marshal(v); err != nil {
|
|
b.Fatal("Marshal:", err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func BenchmarkUnmarshalCWTClaims(b *testing.B) {
|
|
// Data from https://tools.ietf.org/html/rfc8392#appendix-A section A.1
|
|
data := hexDecode("a70175636f61703a2f2f61732e6578616d706c652e636f6d02656572696b77037818636f61703a2f2f6c696768742e6578616d706c652e636f6d041a5612aeb0051a5610d9f0061a5610d9f007420b71")
|
|
for i := 0; i < b.N; i++ {
|
|
var v claims
|
|
if err := Unmarshal(data, &v); err != nil {
|
|
b.Fatal("Unmarshal:", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkUnmarshalCWTClaimsWithDupMapKeyOpt(b *testing.B) {
|
|
// Data from https://tools.ietf.org/html/rfc8392#appendix-A section A.1
|
|
data := hexDecode("a70175636f61703a2f2f61732e6578616d706c652e636f6d02656572696b77037818636f61703a2f2f6c696768742e6578616d706c652e636f6d041a5612aeb0051a5610d9f0061a5610d9f007420b71")
|
|
dm, _ := DecOptions{DupMapKey: DupMapKeyEnforcedAPF}.DecMode()
|
|
for i := 0; i < b.N; i++ {
|
|
var v claims
|
|
if err := dm.Unmarshal(data, &v); err != nil {
|
|
b.Fatal("Unmarshal:", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkMarshalCWTClaims(b *testing.B) {
|
|
// Data from https://tools.ietf.org/html/rfc8392#appendix-A section A.1
|
|
data := hexDecode("a70175636f61703a2f2f61732e6578616d706c652e636f6d02656572696b77037818636f61703a2f2f6c696768742e6578616d706c652e636f6d041a5612aeb0051a5610d9f0061a5610d9f007420b71")
|
|
var v claims
|
|
if err := Unmarshal(data, &v); err != nil {
|
|
b.Fatal("Unmarshal:", err)
|
|
}
|
|
for i := 0; i < b.N; i++ {
|
|
if _, err := Marshal(v); err != nil {
|
|
b.Fatal("Unmarshal:", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkUnmarshalSenML(b *testing.B) {
|
|
// Data from https://tools.ietf.org/html/rfc8428#section-6
|
|
data := hexDecode("87a721781b75726e3a6465763a6f773a3130653230373361303130383030363a22fb41d303a15b00106223614120050067766f6c7461676501615602fb405e066666666666a3006763757272656e74062402fb3ff3333333333333a3006763757272656e74062302fb3ff4cccccccccccda3006763757272656e74062202fb3ff6666666666666a3006763757272656e74062102f93e00a3006763757272656e74062002fb3ff999999999999aa3006763757272656e74060002fb3ffb333333333333")
|
|
for i := 0; i < b.N; i++ {
|
|
var v []SenMLRecord
|
|
if err := Unmarshal(data, &v); err != nil {
|
|
b.Fatal("Unmarshal:", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkMarshalSenML(b *testing.B) {
|
|
// Data from https://tools.ietf.org/html/rfc8428#section-6
|
|
data := hexDecode("87a721781b75726e3a6465763a6f773a3130653230373361303130383030363a22fb41d303a15b00106223614120050067766f6c7461676501615602fb405e066666666666a3006763757272656e74062402fb3ff3333333333333a3006763757272656e74062302fb3ff4cccccccccccda3006763757272656e74062202fb3ff6666666666666a3006763757272656e74062102f93e00a3006763757272656e74062002fb3ff999999999999aa3006763757272656e74060002fb3ffb333333333333")
|
|
var v []SenMLRecord
|
|
if err := Unmarshal(data, &v); err != nil {
|
|
b.Fatal("Unmarshal:", err)
|
|
}
|
|
for i := 0; i < b.N; i++ {
|
|
if _, err := Marshal(v); err != nil {
|
|
b.Fatal("Unmarshal:", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkMarshalSenMLShortestFloat16(b *testing.B) {
|
|
// Data from https://tools.ietf.org/html/rfc8428#section-6
|
|
data := hexDecode("87a721781b75726e3a6465763a6f773a3130653230373361303130383030363a22fb41d303a15b00106223614120050067766f6c7461676501615602fb405e066666666666a3006763757272656e74062402fb3ff3333333333333a3006763757272656e74062302fb3ff4cccccccccccda3006763757272656e74062202fb3ff6666666666666a3006763757272656e74062102f93e00a3006763757272656e74062002fb3ff999999999999aa3006763757272656e74060002fb3ffb333333333333")
|
|
var v []SenMLRecord
|
|
if err := Unmarshal(data, &v); err != nil {
|
|
b.Fatal("Unmarshal:", err)
|
|
}
|
|
em, _ := EncOptions{ShortestFloat: ShortestFloat16}.EncMode()
|
|
for i := 0; i < b.N; i++ {
|
|
if _, err := em.Marshal(v); err != nil {
|
|
b.Fatal("Unmarshal:", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkUnmarshalWebAuthn(b *testing.B) {
|
|
// Data generated from Yubico security key
|
|
data := hexDecode("a363666d74686669646f2d7532666761747453746d74a26373696758483046022100e7ab373cfbd99fcd55fd59b0f6f17fef5b77a20ddec3db7f7e4d55174e366236022100828336b4822125fb56541fb14a8a273876acd339395ec2dad95cf41c1dd2a9ae637835638159024e3082024a30820132a0030201020204124a72fe300d06092a864886f70d01010b0500302e312c302a0603550403132359756269636f2055324620526f6f742043412053657269616c203435373230303633313020170d3134303830313030303030305a180f32303530303930343030303030305a302c312a302806035504030c2159756269636f205532462045452053657269616c203234393431343937323135383059301306072a8648ce3d020106082a8648ce3d030107034200043d8b1bbd2fcbf6086e107471601468484153c1c6d3b4b68a5e855e6e40757ee22bcd8988bf3befd7cdf21cb0bf5d7a150d844afe98103c6c6607d9faae287c02a33b3039302206092b0601040182c40a020415312e332e362e312e342e312e34313438322e312e313013060b2b0601040182e51c020101040403020520300d06092a864886f70d01010b05000382010100a14f1eea0076f6b8476a10a2be72e60d0271bb465b2dfbfc7c1bd12d351989917032631d795d097fa30a26a325634e85721bc2d01a86303f6bc075e5997319e122148b0496eec8d1f4f94cf4110de626c289443d1f0f5bbb239ca13e81d1d5aa9df5af8e36126475bfc23af06283157252762ff68879bcf0ef578d55d67f951b4f32b63c8aea5b0f99c67d7d814a7ff5a6f52df83e894a3a5d9c8b82e7f8bc8daf4c80175ff8972fda79333ec465d806eacc948f1bab22045a95558a48c20226dac003d41fbc9e05ea28a6bb5e10a49de060a0a4f6a2676a34d68c4abe8c61874355b9027e828ca9e064b002d62e8d8cf0744921753d35e3c87c5d5779453e7768617574684461746158c449960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d976341000000000000000000000000000000000000000000408903fd7dfd2c9770e98cae0123b13a2c27828a106349bc6277140e7290b7e9eb7976aa3c04ed347027caf7da3a2fa76304751c02208acfc4e7fc6c7ebbc375c8a5010203262001215820ad7f7992c335b90d882b2802061b97a4fabca7e2ee3e7a51e728b8055e4eb9c7225820e0966ba7005987fece6f0e0e13447aa98cec248e4000a594b01b74c1cb1d40b3")
|
|
for i := 0; i < b.N; i++ {
|
|
var v attestationObject
|
|
if err := Unmarshal(data, &v); err != nil {
|
|
b.Fatal("Unmarshal:", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkMarshalWebAuthn(b *testing.B) {
|
|
// Data generated from Yubico security key
|
|
data := hexDecode("a363666d74686669646f2d7532666761747453746d74a26373696758483046022100e7ab373cfbd99fcd55fd59b0f6f17fef5b77a20ddec3db7f7e4d55174e366236022100828336b4822125fb56541fb14a8a273876acd339395ec2dad95cf41c1dd2a9ae637835638159024e3082024a30820132a0030201020204124a72fe300d06092a864886f70d01010b0500302e312c302a0603550403132359756269636f2055324620526f6f742043412053657269616c203435373230303633313020170d3134303830313030303030305a180f32303530303930343030303030305a302c312a302806035504030c2159756269636f205532462045452053657269616c203234393431343937323135383059301306072a8648ce3d020106082a8648ce3d030107034200043d8b1bbd2fcbf6086e107471601468484153c1c6d3b4b68a5e855e6e40757ee22bcd8988bf3befd7cdf21cb0bf5d7a150d844afe98103c6c6607d9faae287c02a33b3039302206092b0601040182c40a020415312e332e362e312e342e312e34313438322e312e313013060b2b0601040182e51c020101040403020520300d06092a864886f70d01010b05000382010100a14f1eea0076f6b8476a10a2be72e60d0271bb465b2dfbfc7c1bd12d351989917032631d795d097fa30a26a325634e85721bc2d01a86303f6bc075e5997319e122148b0496eec8d1f4f94cf4110de626c289443d1f0f5bbb239ca13e81d1d5aa9df5af8e36126475bfc23af06283157252762ff68879bcf0ef578d55d67f951b4f32b63c8aea5b0f99c67d7d814a7ff5a6f52df83e894a3a5d9c8b82e7f8bc8daf4c80175ff8972fda79333ec465d806eacc948f1bab22045a95558a48c20226dac003d41fbc9e05ea28a6bb5e10a49de060a0a4f6a2676a34d68c4abe8c61874355b9027e828ca9e064b002d62e8d8cf0744921753d35e3c87c5d5779453e7768617574684461746158c449960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d976341000000000000000000000000000000000000000000408903fd7dfd2c9770e98cae0123b13a2c27828a106349bc6277140e7290b7e9eb7976aa3c04ed347027caf7da3a2fa76304751c02208acfc4e7fc6c7ebbc375c8a5010203262001215820ad7f7992c335b90d882b2802061b97a4fabca7e2ee3e7a51e728b8055e4eb9c7225820e0966ba7005987fece6f0e0e13447aa98cec248e4000a594b01b74c1cb1d40b3")
|
|
var v attestationObject
|
|
if err := Unmarshal(data, &v); err != nil {
|
|
b.Fatal("Unmarshal:", err)
|
|
}
|
|
for i := 0; i < b.N; i++ {
|
|
if _, err := Marshal(v); err != nil {
|
|
b.Fatal("Marshal:", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkUnmarshalCOSEMAC(b *testing.B) {
|
|
// Data from https://tools.ietf.org/html/rfc8392#appendix-A section A.4
|
|
data := hexDecode("d83dd18443a10104a1044c53796d6d65747269633235365850a70175636f61703a2f2f61732e6578616d706c652e636f6d02656572696b77037818636f61703a2f2f6c696768742e6578616d706c652e636f6d041a5612aeb0051a5610d9f0061a5610d9f007420b7148093101ef6d789200")
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
var v macedCOSE
|
|
if err := Unmarshal(data, &v); err != nil {
|
|
b.Fatal("Unmarshal:", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkUnmarshalCOSEMACWithTag(b *testing.B) {
|
|
// Data from https://tools.ietf.org/html/rfc8392#appendix-A section A.4
|
|
data := hexDecode("d83dd18443a10104a1044c53796d6d65747269633235365850a70175636f61703a2f2f61732e6578616d706c652e636f6d02656572696b77037818636f61703a2f2f6c696768742e6578616d706c652e636f6d041a5612aeb0051a5610d9f0061a5610d9f007420b7148093101ef6d789200")
|
|
|
|
// Register tag CBOR Web Token (CWT) 61 and COSE_Mac0 17 with macedCOSE type
|
|
tags := NewTagSet()
|
|
if err := tags.Add(TagOptions{EncTag: EncTagRequired, DecTag: DecTagRequired}, reflect.TypeOf(macedCOSE{}), 61, 17); err != nil {
|
|
b.Fatal("TagSet.Add:", err)
|
|
}
|
|
|
|
// Create DecMode with tags
|
|
dm, _ := DecOptions{}.DecModeWithTags(tags)
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
var v macedCOSE
|
|
if err := dm.Unmarshal(data, &v); err != nil {
|
|
b.Fatal("Unmarshal:", err)
|
|
}
|
|
}
|
|
}
|
|
func BenchmarkMarshalCOSEMAC(b *testing.B) {
|
|
// Data from https://tools.ietf.org/html/rfc8392#appendix-A section A.4
|
|
data := hexDecode("d83dd18443a10104a1044c53796d6d65747269633235365850a70175636f61703a2f2f61732e6578616d706c652e636f6d02656572696b77037818636f61703a2f2f6c696768742e6578616d706c652e636f6d041a5612aeb0051a5610d9f0061a5610d9f007420b7148093101ef6d789200")
|
|
|
|
var v macedCOSE
|
|
if err := Unmarshal(data, &v); err != nil {
|
|
b.Fatal("Unmarshal():", err)
|
|
}
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
if _, err := Marshal(v); err != nil {
|
|
b.Fatal("Marshal():", v, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkMarshalCOSEMACWithTag(b *testing.B) {
|
|
// Data from https://tools.ietf.org/html/rfc8392#appendix-A section A.4
|
|
data := hexDecode("d83dd18443a10104a1044c53796d6d65747269633235365850a70175636f61703a2f2f61732e6578616d706c652e636f6d02656572696b77037818636f61703a2f2f6c696768742e6578616d706c652e636f6d041a5612aeb0051a5610d9f0061a5610d9f007420b7148093101ef6d789200")
|
|
|
|
// Register tag CBOR Web Token (CWT) 61 and COSE_Mac0 17 with macedCOSE type
|
|
tags := NewTagSet()
|
|
if err := tags.Add(TagOptions{EncTag: EncTagRequired, DecTag: DecTagRequired}, reflect.TypeOf(macedCOSE{}), 61, 17); err != nil {
|
|
b.Fatal("TagSet.Add:", err)
|
|
}
|
|
|
|
// Create EncMode with tags.
|
|
dm, _ := DecOptions{}.DecModeWithTags(tags)
|
|
em, _ := EncOptions{}.EncModeWithTags(tags)
|
|
|
|
var v macedCOSE
|
|
if err := dm.Unmarshal(data, &v); err != nil {
|
|
b.Fatal("Unmarshal():", err)
|
|
}
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
if _, err := em.Marshal(v); err != nil {
|
|
b.Fatal("Marshal():", v, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkUnmarshalMapToStruct(b *testing.B) {
|
|
type S struct {
|
|
A, B, C, D, E, F, G, H, I, J, K, L, M bool
|
|
}
|
|
|
|
var (
|
|
allKnownFields = hexDecode("ad6141f56142f56143f56144f56145f56146f56147f56148f56149f5614af5614bf5614cf5614df5") // {"A": true, ... "M": true }
|
|
allKnownDuplicateFields = hexDecode("ad6141f56141f56141f56141f56141f56141f56141f56141f56141f56141f56141f56141f56141f5") // {"A": true, "A": true, "A": true, ...}
|
|
allUnknownFields = hexDecode("ad614ef5614ff56150f56151f56152f56153f56154f56155f56156f56157f56158f56159f5615af5") // {"N": true, ... "Z": true }
|
|
allUnknownDuplicateFields = hexDecode("ad614ef5614ef5614ef5614ef5614ef5614ef5614ef5614ef5614ef5614ef5614ef5614ef5614ef5") // {"N": true, "N": true, "N": true, ...}
|
|
)
|
|
|
|
type ManyFields struct {
|
|
AA, AB, AC, AD, AE, AF, AG, AH, AI, AJ, AK, AL, AM, AN, AO, AP, AQ, AR, AS, AT, AU, AV, AW, AX, AY, AZ bool
|
|
BA, BB, BC, BD, BE, BF, BG, BH, BI, BJ, BK, BL, BM, BN, BO, BP, BQ, BR, BS, BT, BU, BV, BW, BX, BY, BZ bool
|
|
CA, CB, CC, CD, CE, CF, CG, CH, CI, CJ, CK, CL, CM, CN, CO, CP, CQ, CR, CS, CT, CU, CV, CW, CX, CY, CZ bool
|
|
DA, DB, DC, DD, DE, DF, DG, DH, DI, DJ, DK, DL, DM, DN, DO, DP, DQ, DR, DS, DT, DU, DV, DW, DX, DY, DZ bool
|
|
}
|
|
var manyFieldsOneKeyPerField []byte
|
|
{
|
|
// An EncOption that accepts a function to sort or shuffle keys might be useful for
|
|
// cases like this. Here we are manually encoding the fields in reverse order to
|
|
// target worst-case key-to-field matching.
|
|
rt := reflect.TypeOf(ManyFields{})
|
|
var buf bytes.Buffer
|
|
if rt.NumField() > 255 {
|
|
b.Fatalf("invalid test assumption: ManyFields expected to have no more than 255 fields, has %d", rt.NumField())
|
|
}
|
|
buf.WriteByte(0xb8)
|
|
buf.WriteByte(byte(rt.NumField()))
|
|
for i := rt.NumField() - 1; i >= 0; i-- { // backwards
|
|
f := rt.Field(i)
|
|
if len(f.Name) > 23 {
|
|
b.Fatalf("invalid test assumption: field name %q longer than 23 bytes", f.Name)
|
|
}
|
|
buf.WriteByte(byte(0x60 + len(f.Name)))
|
|
buf.WriteString(f.Name)
|
|
buf.WriteByte(0xf5) // true
|
|
}
|
|
manyFieldsOneKeyPerField = buf.Bytes()
|
|
}
|
|
|
|
type input struct {
|
|
name string
|
|
data []byte
|
|
into any
|
|
reject bool
|
|
}
|
|
|
|
for _, tc := range []*struct {
|
|
name string
|
|
opts DecOptions
|
|
inputs []input
|
|
}{
|
|
{
|
|
name: "default options",
|
|
opts: DecOptions{},
|
|
inputs: []input{
|
|
{
|
|
name: "all known fields",
|
|
data: allKnownFields,
|
|
into: S{},
|
|
reject: false,
|
|
},
|
|
{
|
|
name: "all known duplicate fields",
|
|
data: allKnownDuplicateFields,
|
|
into: S{},
|
|
reject: false,
|
|
},
|
|
{
|
|
name: "all unknown fields",
|
|
data: allUnknownFields,
|
|
into: S{},
|
|
reject: false,
|
|
},
|
|
{
|
|
name: "all unknown duplicate fields",
|
|
data: allUnknownDuplicateFields,
|
|
into: S{},
|
|
reject: false,
|
|
},
|
|
{
|
|
name: "many fields one key per field",
|
|
data: manyFieldsOneKeyPerField,
|
|
into: ManyFields{},
|
|
reject: false,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "reject unknown",
|
|
opts: DecOptions{ExtraReturnErrors: ExtraDecErrorUnknownField},
|
|
inputs: []input{
|
|
{
|
|
name: "all known fields",
|
|
data: allKnownFields,
|
|
into: S{},
|
|
reject: false,
|
|
},
|
|
{
|
|
name: "all known duplicate fields",
|
|
data: allKnownDuplicateFields,
|
|
into: S{},
|
|
reject: false,
|
|
},
|
|
{
|
|
name: "all unknown fields",
|
|
data: allUnknownFields,
|
|
into: S{},
|
|
reject: true,
|
|
},
|
|
{
|
|
name: "all unknown duplicate fields",
|
|
data: allUnknownDuplicateFields,
|
|
into: S{},
|
|
reject: true,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "reject duplicate",
|
|
opts: DecOptions{DupMapKey: DupMapKeyEnforcedAPF},
|
|
inputs: []input{
|
|
{
|
|
name: "all known fields",
|
|
data: allKnownFields,
|
|
into: S{},
|
|
reject: false,
|
|
},
|
|
{
|
|
name: "all known duplicate fields",
|
|
data: allKnownDuplicateFields,
|
|
into: S{},
|
|
reject: true,
|
|
},
|
|
{
|
|
name: "all unknown fields",
|
|
data: allUnknownFields,
|
|
into: S{},
|
|
reject: false,
|
|
},
|
|
{
|
|
name: "all unknown duplicate fields",
|
|
data: allUnknownDuplicateFields,
|
|
into: S{},
|
|
reject: true,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "reject unknown and duplicate",
|
|
opts: DecOptions{
|
|
DupMapKey: DupMapKeyEnforcedAPF,
|
|
ExtraReturnErrors: ExtraDecErrorUnknownField,
|
|
},
|
|
inputs: []input{
|
|
{
|
|
name: "all known fields",
|
|
data: allKnownFields,
|
|
into: S{},
|
|
reject: false,
|
|
},
|
|
{
|
|
name: "all known duplicate fields",
|
|
data: allKnownDuplicateFields,
|
|
into: S{},
|
|
reject: true,
|
|
},
|
|
{
|
|
name: "all unknown fields",
|
|
data: allUnknownFields,
|
|
into: S{},
|
|
reject: true,
|
|
},
|
|
{
|
|
name: "all unknown duplicate fields",
|
|
data: allUnknownDuplicateFields,
|
|
into: S{},
|
|
reject: true,
|
|
},
|
|
},
|
|
},
|
|
} {
|
|
for _, in := range tc.inputs {
|
|
b.Run(fmt.Sprintf("%s/%s", tc.name, in.name), func(b *testing.B) {
|
|
dm, err := tc.opts.DecMode()
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
|
|
dst := reflect.New(reflect.TypeOf(in.into)).Interface()
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
if err := dm.Unmarshal(in.data, dst); !in.reject && err != nil {
|
|
b.Fatalf("unexpected error: %v", err)
|
|
} else if in.reject && err == nil {
|
|
b.Fatal("expected non-nil error")
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|