This module implements a Roughtime client for Node.js v6.x and up.
Roughtime is a project that aims to provide secure time synchronisation.
With NTP, a third party can intercept and modify replies from the server. The reply you get is not necessarily and certainly not provably what the server sent.
Roughtime replies cannot be forged: they are cryptographically signed using Ed25519. Clients can also create audit trails to help weed out misbehaving servers (another common problem with NTP.)
See the Roughtime homepage for more information.
-
Midpoint is the server's idea of "now" relative to the UNIX epoch, expressed in microseconds.
-
Radius is the server's uncertainty about the midpoint, also expressed in microseconds.
The server asserts that the true time is within midpoint - radius/2
and
midpoint + radius/2
.
Return-trip network latency is not accounted for. Expect that to be on the order of several milliseconds.
Leap seconds are smeared out over the course of a day.
Good ol' callback-style:
const roughtime = require('roughtime')
roughtime('roughtime.cloudflare.com', (err, result) => {
if (err) throw err
const {midpoint, radius} = result
console.log(midpoint, radius) // ex. "1537907399109000 1000000"
console.log(new Date(midpoint / 1e3)) // ex. "2018-09-25T20:29:59.109Z"
})
With promises:
const {promise: roughtime} = require('roughtime')
roughtime('roughtime.cloudflare.com').then(result => {
const {midpoint, radius} = result
console.log(midpoint, radius) // ex. "1537907399109000 1000000"
})
Or with async/await:
const {promise: roughtime} = require('roughtime')
async function f() {
const {midpoint, radius} = await roughtime('roughtime.cloudflare.com')
console.log(midpoint, radius) // ex. "1537907399109000 1000000"
}
f() // no top-level await yet in Node.js
roughtime
currently knows about two public servers:
roughtime.cloudflare.com
roughtime.sandbox.google.com
To query other servers, provide the host name and optionally the port number, and include the server's public key as a Buffer or Uint8Array:
const roughtime = require('roughtime')
const pubkey = Uint8Array.from([0,0,0,0,/*...*/]) // must be 32 bytes
const options = {
host: 'roughtime.example.com',
port: 1337, // default is 2002
pubkey: pubkey,
}
roughtime(options, (err, result) => {
// ...
})
If you want to plug in your own nonce or UDP socket, you can: the options are
called .nonce
and .socket
respectively. The nonce must be a 64 byte
Buffer or Uint8Array:
const roughtime = require('roughtime')
const {randomBytes} = require('crypto')
const host = 'roughtime.cloudflare.com'
const nonce = randomBytes(64)
const options = {host, nonce}
roughtime(options, (err, result) => {
// ...
})
-
Auditing is not implemented. The ecosystem isn't large enough yet to make it practical.
-
Merkle tree verification has only been lightly tested. I have yet to see a server in the wild return a reply that contains one.