KIP core concept Sum

Checksum information is part of the lower-level API that KIP itself uses.

The Sum class collects checksum information, and can be updated with new data at any time. It offers a few advanced facilities, such as forking or cloning the hash and marking syntactical spots of interest that should not cause security problems as a result of invisible binary boundaries.

The need for a separate checksum is not just because of the more powerful functionality than the MAC included in kip_up(), but there are strong security reasons, such as the number of bits involved, the data spanned and the longevity of the data. Try to think of the MAC as a short-lived, message-specific protection against accidental changes, whereas a Sum protects against deliberate assaults on your security. And yes, it takes some determination to mount an attack on a MAC and if you test it a few times by hand you should see you bit changes or byte removals trigger alerts quite consistently; but if you really wanted to put in the effort and compute power you would probably find a way to trick the MAC. Not so with the Sum. So when you need to protect anything but messages in transit as KIP does for its internal purposes, use a Sum. Really, don't be shy and just always use a Sum.

Every internal Key has a Sum attached to it. Not all Sum instances are also Key instances, though.

Interface. A few useful calls for the Sum class:

  • Sum(context,keyid) creates a new Sum object, to manage the checksum with the support of the identified key. Note that every Key already has a Sum builtin by being a subclass hereof. Note that "keyid" is actually a sum-or-key-id, which is a larger set of values than just key-id.

  • sumid() returns the identity for this Sum. Note that the set of all sum identities includes the set of all key identities, because every Key has a Sum built in. This is a superset, the reverse need not be true. It is true however that every Sum connects to one Key.

  • append(bytes) appends data bytes to this Sum object or, if this object happens to also be a Key, insert it between data that passes through kip_up() and kip_down() calls.

  • restart() the Sum object in a state that has not seen any data passing in yet. This works for Key objects too, and then forgets all kip_up() and kip_down() data too.

  • fork() the Sum in its current state, and allow the old and new to continue in different or same directions without any further relation; do however share the history up to the moment of this fork() call. The forked Sum will be tied to the same Key, but it will not be updated by its kip_up() and kip_down() operations, while that aspect of the original Sum continues to exist or not, as before.

  • mark(typing=None) inserts a separation marker into the hash flow. This is a new idea. It allows clear separation between bits that must never been seen to connect, and follows the basic philosophy that hash input is secure if it could be parsed back. In this case, markers are inserted in the input flow, as well as an extra one at the end, in a reproducable manner that requires no escaping and no special characters. To yield the best possible result, you could add a textual hint about the marker point, such as a syntactical choice made on account of prior and/or following data. Providing no typing differs from providing any string value, even an empty string. You are welcome to use international type; we will map it in a repeatable manner to a sequence of bytes. Note that it is text, so there are no intermediate 0x00 bytes. This imposes no restrictions on the other bytes, though.

  • merge(*addends) other sums' current/intermediate hash values into this one and then continue. This allows the merging of data flows. The addends are processed in the order in which they appear as arguments.

  • sign() produces signature mud for the current Sum state, where the bound Key is used to produce the signature. Note that every Sum has an associated Key, not just the ones that happen to play the role of Key through subclassing. Operations like sum_start() and fork() always share the Key ID into the newly created Sum object.

  • verify() checks signature mud bytes against the current Sum state, and use the bound Key to verify the signature. To make this work, the same Key ID must have been associated with this Sum as was shared before the verified sign() call; that is the responsibility for the application programmer.