Skip to main content

Hashable JSON

· 2 min read
Peter Johnson

Object keys in a Javascript maintain insertion order.

For some crypto tasks, such as hashing and signing, it's desirable to have a normalized view of the data.

Fortunately it's easy enough to recursively sort object keys using just a few lines of code:

function replacer (key, value) {
switch (Object.prototype.toString.call(value)) {

// sort object keys lexicographically
case '[object Object]':
return Object.fromEntries(Object.entries(value).sort())

default:
return value
}
}

Example

You can use it as you normally would with JSON.stringify():

const example = {
"isbn": "123-456-222",
"author": {
"lastname": "Doe",
"firstname": "Jane"
},
"editor": {
"lastname": "Smith",
"firstname": "Jane"
},
"title": "The Ultimate Database Study Guide",
"category": [
"Non-Fiction",
"Technology"
]
}

> JSON.stringify(example, replacer, 2)

{
"author": {
"firstname": "Jane",
"lastname": "Doe"
},
"category": [
"Non-Fiction",
"Technology"
],
"editor": {
"firstname": "Jane",
"lastname": "Smith"
},
"isbn": "123-456-222",
"title": "The Ultimate Database Study Guide"
}

Additional types

It's also possible to extend this method to other types:

function replacer (key, value) {
switch (Object.prototype.toString.call(value)) {

// sort object keys lexicographically
case '[object Object]':
return Object.fromEntries(Object.entries(value).sort())

// Unicode Normalization Form KC
case '[object String]':
return value.normalize('NFKC')

// round floats to 7 decimal places of precision
case '[object Number]':
return value % 1 === 0
? value
: Math.round(parseFloat(value) * 1e7) / 1e7

default:
return value
}
}