1 /* 2 Copyright 2024 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package modes 18 19 import ( 20 "github.com/fxamacker/cbor/v2" 21 ) 22 23 var Encode cbor.EncMode = func() cbor.EncMode { 24 encode, err := cbor.EncOptions{ 25 // Map keys need to be sorted to have deterministic output, and this is the order 26 // defined in RFC 8949 4.2.1 "Core Deterministic Encoding Requirements". 27 Sort: cbor.SortBytewiseLexical, 28 29 // CBOR supports distinct types for IEEE-754 float16, float32, and float64. Store 30 // floats in the smallest width that preserves value so that equivalent float32 and 31 // float64 values encode to identical bytes, as they do in a JSON 32 // encoding. Satisfies one of the "Core Deterministic Encoding Requirements". 33 ShortestFloat: cbor.ShortestFloat16, 34 35 // ShortestFloat doesn't apply to NaN or Inf values. Inf values are losslessly 36 // encoded to float16. RFC 8949 recommends choosing a single representation of NaN 37 // in applications that do not smuggle additional information inside NaN values, we 38 // use 0x7e00. 39 NaNConvert: cbor.NaNConvert7e00, 40 InfConvert: cbor.InfConvertFloat16, 41 42 // Prefer encoding math/big.Int to one of the 64-bit integer types if it fits. When 43 // later decoded into Unstructured, the set of allowable concrete numeric types is 44 // limited to int64 and float64, so the distinction between big integer and integer 45 // can't be preserved. 46 BigIntConvert: cbor.BigIntConvertShortest, 47 48 // MarshalJSON for time.Time writes RFC3339 with nanos. 49 Time: cbor.TimeRFC3339Nano, 50 51 // The decoder must be able to accept RFC3339 strings with or without tag 0 (e.g. by 52 // the end of time.Time -> JSON -> Unstructured -> CBOR, the CBOR encoder has no 53 // reliable way of knowing that a particular string originated from serializing a 54 // time.Time), so producing tag 0 has little use. 55 TimeTag: cbor.EncTagNone, 56 57 // Indefinite-length items have multiple encodings and aren't being used anyway, so 58 // disable to avoid an opportunity for nondeterminism. 59 IndefLength: cbor.IndefLengthForbidden, 60 61 // Preserve distinction between nil and empty for slices and maps. 62 NilContainers: cbor.NilContainerAsNull, 63 64 // OK to produce tags. 65 TagsMd: cbor.TagsAllowed, 66 67 // Use the same definition of "empty" as encoding/json. 68 OmitEmpty: cbor.OmitEmptyGoValue, 69 70 // The CBOR types text string and byte string are structurally equivalent, with the 71 // semantic difference that a text string whose content is an invalid UTF-8 sequence 72 // is itself invalid. We reject all invalid text strings at decode time and do not 73 // validate or sanitize all Go strings at encode time. Encoding Go strings to the 74 // byte string type is comparable to the existing Protobuf behavior and cheaply 75 // ensures that the output is valid CBOR. 76 String: cbor.StringToByteString, 77 78 // Encode struct field names to the byte string type rather than the text string 79 // type. 80 FieldName: cbor.FieldNameToByteString, 81 }.EncMode() 82 if err != nil { 83 panic(err) 84 } 85 return encode 86 }() 87 88 var EncodeNondeterministic cbor.EncMode = func() cbor.EncMode { 89 opts := Encode.EncOptions() 90 opts.Sort = cbor.SortNone 91 em, err := opts.EncMode() 92 if err != nil { 93 panic(err) 94 } 95 return em 96 }() 97