SwiftCBOR icon indicating copy to clipboard operation
SwiftCBOR copied to clipboard

Incorrect encoding of negative 64 bit int

Open Sajjon opened this issue 5 years ago • 1 comments

Hello! Thanks for a great library!

I noticed that the encoding of negative 64 bit integers are wrong. You need to subtract 1 to get the correct value. See the RFC 7049

Major type 1:  a negative integer.  The encoding follows the rules
      for unsigned integers (major type 0), except that the value is
      then -1 minus the encoded unsigned integer.  For example, the
      integer -500 would be 0b001_11001 (major type 1, additional
      information 25) followed by the two bytes 0x01f3, which is 499 in
      decimal.

But you are doing the two's complement:

    public static func encodeNegativeInt(_ x: Int64) -> [UInt8] {
        assert(x < 0)
        var res = encodeVarUInt(~UInt64(bitPattern: x))
        res[0] = res[0] | 0b001_00000
        return res
    }

I got it working by subtracting 1. I also added a static func accepting Int64, like this:

public extension CBOR {
    static func int64(_ int: Int64) -> CBOR {
        if int < 0 {
            return CBOR.negativeInt(UInt64(abs(int)-1))
        } else {
            return CBOR.unsignedInt(UInt64(int))
        }
    }
}

You could probably add a few test cases in your unit test where you explicitly test UInt64 :)

Thx!

Sajjon avatar Apr 02 '19 20:04 Sajjon

NegativeInt not storing the actual usable number is intentional — to make encoded negative max int representable — and mentioned in the readme:

Negative integers are decoded as NegativeInt(UInt), where the actual number is -1 - i (CBOR's negative integers can be larger than 64-bit signed integers).

I guess convenience functions like your int64 would be good, I'd accept a PR with that.

valpackett avatar Apr 02 '19 21:04 valpackett