pamoja for TypeScript - v0.2.0
    Preparing search index...

    Module @pamoja/security

    Ergonomic facade over the generated device-identity binding.

    Adds string-or-bytes payloads and a named constructor, without adding behavior; the signing and verifying happen in the native core reached through the generated contract.

    @pamoja/security

    ed25519 device identity: sign a reading and verify it, so a gateway can prove it is authentic. One capability of pamoja, one memory-safe Rust core with bindings for TypeScript, Python, and C#.

    read the guide documentation API reference

    npm install @pamoja/security
    

    This pulls in @pamoja/native, the compiled engine. npm install pamoja is the whole framework in one package.

    The test that runs in CI, spliced here as it ran.

    From bindings/node/guides/security.ts:

    import { DeviceIdentity, fingerprint, verify, verifyMessage } from '@pamoja/security'

    // The seed is provisioned into the device once and never leaves it. A real one comes from
    // the factory or a secure element; any 32 bytes stand in here.
    const device = DeviceIdentity.fromSeed(Buffer.alloc(32, 7))

    // Only the 32-byte public key travels to the gateway. Its fingerprint is the short form an
    // operator reads off a screen to tell one device from another.
    const gatewayKey = device.publicKey()
    console.log(`device ${fingerprint(gatewayKey)}`)

    // Signing is deterministic, so the same reading always produces the same 64 bytes and there
    // is no randomness to get wrong on a microcontroller.
    const reading = 'meter-4 1182.750 kWh'
    const signature = device.sign(reading)
    if (verify(gatewayKey, reading, signature)) {
    console.log(`accepted ${reading}`)
    } else {
    console.log('rejected a reading the device really did sign, which should never happen')
    }

    // A digit changed in transit no longer matches what was signed.
    const edited = 'meter-4 1082.750 kWh'
    if (verify(gatewayKey, edited, signature)) {
    console.log('accepted an edited reading, which should never happen')
    } else {
    console.log(`rejected ${edited}`)
    }

    // Nor does the same reading offered under another device's key.
    const impostor = DeviceIdentity.fromSeed(Buffer.alloc(32, 90))
    if (verify(impostor.publicKey(), reading, signature)) {
    console.log('accepted an impostor, which should never happen')
    } else {
    console.log("rejected a signature offered under another device's key")
    }

    // On a link the signature and the reading usually travel as one message, signature first,
    // and the gateway gets the reading back only once it has checked it.
    const message = device.signMessage(reading)
    const size = message.length
    console.log(`message ${size} bytes on the wire, the signature and the reading together`)
    const carried = verifyMessage(gatewayKey, message)
    if (carried) {
    console.log(`accepted ${carried.toString()}, read out of the message`)
    } else {
    console.log('rejected a message the device really did sign, which should never happen')
    }

    // A message that lost its last byte on the way is refused whole.
    if (verifyMessage(gatewayKey, message.subarray(0, size - 1))) {
    console.log('accepted a message cut short, which should never happen')
    } else {
    console.log('rejected a message that lost its last byte on the way')
    }
    Language Package Reference
    Rust pamoja-security reference, docs.rs, install
    TypeScript @pamoja/security reference, install
    Python pamoja-security reference, install
    C# Pamoja.Security reference, install

    MIT

    DeviceIdentity
    Payload
    fingerprint
    verify
    verifyMessage