/* eslint-disable camelcase */ const test = require('brittle') const sodium = require('..') const fixtures = require('./fixtures/crypto_sign.json') test('crypto_sign_ed25519_sk_to_pk', function (t) { const pk = Buffer.alloc(sodium.crypto_sign_PUBLICKEYBYTES) const pke = Buffer.alloc(sodium.crypto_sign_PUBLICKEYBYTES) const sk = Buffer.alloc(sodium.crypto_sign_SECRETKEYBYTES) sodium.crypto_sign_keypair(pk, sk) sodium.crypto_sign_ed25519_sk_to_pk(pke, sk) t.ok(pk.equals(pke)) }) test('crypto_sign_seed_keypair', function (t) { const pk = Buffer.alloc(sodium.crypto_sign_PUBLICKEYBYTES) const sk = Buffer.alloc(sodium.crypto_sign_SECRETKEYBYTES) const seed = Buffer.alloc(sodium.crypto_sign_SEEDBYTES, 'lo') t.exception.all(function () { sodium.crypto_sign_seed_keypair() }, 'should validate input') t.exception.all(function () { sodium.crypto_sign_seed_keypair(Buffer.alloc(0), Buffer.alloc(0), Buffer.alloc(0)) }, 'should validate input length') sodium.crypto_sign_seed_keypair(pk, sk, seed) const eSk = '6c6f6c6f6c6f6c6f6c6f6c6f6c6f6c6f6c6f6c6f6c6f6c6f6c6f6c6f6c6f6c6f41eb5b4dba29b19e391d9a4d1a4a879b27958ff3734e10cfbf1f46d68f4d3038' const ePk = '41eb5b4dba29b19e391d9a4d1a4a879b27958ff3734e10cfbf1f46d68f4d3038' t.alike(pk.toString('hex'), ePk, 'seeded public key') t.alike(sk.toString('hex'), eSk, 'seeded secret key') }) test('crypto_sign_keypair', function (t) { const pk = Buffer.alloc(sodium.crypto_sign_PUBLICKEYBYTES) const sk = Buffer.alloc(sodium.crypto_sign_SECRETKEYBYTES) sodium.crypto_sign_keypair(pk, sk) t.not(pk, Buffer.alloc(pk.length), 'made public key') t.not(sk, Buffer.alloc(sk.length), 'made secret key') t.exception.all(function () { sodium.crypto_sign_keypair() }, 'should validate input') t.exception.all(function () { sodium.crypto_sign_keypair(Buffer.alloc(0), Buffer.alloc(0)) }, 'should validate input length') }) test('crypto_sign', function (t) { const pk = Buffer.alloc(sodium.crypto_sign_PUBLICKEYBYTES) const sk = Buffer.alloc(sodium.crypto_sign_SECRETKEYBYTES) sodium.crypto_sign_keypair(pk, sk) const message = Buffer.from('Hello, World!') const signedMessage = Buffer.alloc(message.length + sodium.crypto_sign_BYTES) sodium.crypto_sign(signedMessage, message, sk) t.alike(signedMessage.slice(-message.length), message, 'contains message') const output = Buffer.alloc(message.length) t.absent(sodium.crypto_sign_open(output, Buffer.alloc(signedMessage.length), pk), 'was not signed') t.ok(sodium.crypto_sign_open(output, signedMessage, pk), 'was signed') t.alike(output, message, 'same message') }) test('crypto_sign_detached', function (t) { const pk = Buffer.alloc(sodium.crypto_sign_PUBLICKEYBYTES) const sk = Buffer.alloc(sodium.crypto_sign_SECRETKEYBYTES) sodium.crypto_sign_keypair(pk, sk) const message = Buffer.from('Hello, World!') const signature = Buffer.alloc(sodium.crypto_sign_BYTES) sodium.crypto_sign_detached(signature, message, sk) t.absent(sodium.crypto_sign_verify_detached(Buffer.concat([Buffer.alloc(1), signature]), message, pk), 'was not signed') t.ok(sodium.crypto_sign_verify_detached(signature, message, pk), 'was signed') }) test('crypto_sign_open fixtures', function (t) { for (let i = 0; i < fixtures.length; i++) { const publicKey = new Uint8Array(fixtures[i][1]) const message = new Uint8Array(fixtures[i][3]) const signed = new Uint8Array([].concat(fixtures[i][2], fixtures[i][3])) if (!sodium.crypto_sign_open(message, signed, publicKey)) { t.fail('Failed on fixture #' + i) t.end() return } } t.pass('Passed all fixtures') t.end() }) test('crypto_sign fixtures', function (t) { const fixtures = require('./fixtures/crypto_sign.json') for (let i = 0; i < fixtures.length; i++) { const secretKey = new Uint8Array([].concat(fixtures[i][0], fixtures[i][1])) const message = new Uint8Array(fixtures[i][3]) const expected = new Uint8Array([].concat(fixtures[i][2], fixtures[i][3])) const actual = new Uint8Array(sodium.crypto_sign_BYTES + message.length) sodium.crypto_sign(actual, message, secretKey) if (Buffer.compare(actual, expected) !== 0) { t.fail('Failed on fixture #' + i) t.end() return } } t.pass('Passed all fixtures') t.end() }) test('crypto_sign_verify_detached fixtures', function (t) { const fixtures = require('./fixtures/crypto_sign.json') for (let i = 0; i < fixtures.length; i++) { const publicKey = new Uint8Array(fixtures[i][1]) const message = new Uint8Array(fixtures[i][3]) const signature = new Uint8Array(fixtures[i][2]) if (!sodium.crypto_sign_verify_detached(signature, message, publicKey)) { t.fail('Failed on fixture #' + i) t.end() return } } t.pass('Passed all fixtures') t.end() }) test('crypto_sign_detached fixtures', function (t) { const fixtures = require('./fixtures/crypto_sign.json') for (let i = 0; i < fixtures.length; i++) { const secretKey = new Uint8Array([].concat(fixtures[i][0], fixtures[i][1])) const message = new Uint8Array(fixtures[i][3]) const expected = new Uint8Array(fixtures[i][2]) const actual = new Uint8Array(sodium.crypto_sign_BYTES) sodium.crypto_sign_detached(actual, message, secretKey) if (Buffer.compare(actual, expected) !== 0) { t.fail('Failed on fixture #' + i) t.end() return } } t.pass('Passed all fixtures') t.end() }) /* eslint-disable camelcase */ test('libsodium', function (t) { const sig = new Uint8Array(sodium.crypto_sign_BYTES) const sm = new Uint8Array(1024 + sodium.crypto_sign_BYTES) const skpk = new Uint8Array(sodium.crypto_sign_SECRETKEYBYTES) const pk = new Uint8Array(sodium.crypto_sign_PUBLICKEYBYTES) const sk = new Uint8Array(sodium.crypto_sign_SECRETKEYBYTES) let smlen let i let test sig.fill(0) let pass = true for (i = 0; i < fixtures.length; i++) { test = parseTest(fixtures[i]) skpk.set(test.sk) skpk.set(test.pk, sodium.crypto_sign_SEEDBYTES) smlen = sodium.crypto_sign_BYTES + test.m.byteLength sodium.crypto_sign(sm.subarray(0, test.m.byteLength + sodium.crypto_sign_BYTES), test.m, skpk) pass &= Buffer.compare(test.sig, sm.subarray(0, 64)) === 0 pass &= sodium.crypto_sign_open(test.m, sm.subarray(0, smlen), test.pk) sodium.crypto_sign_detached(sig, test.m, skpk) pass &= sig.byteLength !== 0 && sig.byteLength <= sodium.crypto_sign_BYTES pass &= Buffer.compare(test.sig, sig) === 0 pass &= sodium.crypto_sign_verify_detached(sig, test.m.subarray(0, i), test.pk) if (!pass) t.fail('failed on fixture #' + i) } t.pass('passed all fixtures') for (let j = 1; j < 8; j++) { sig[63] ^= (j << 5) t.absent(sodium.crypto_sign_verify_detached(sig, test.m.subarray(0, i), test.pk)) sig[63] ^= (j << 5) } pk.fill(0) t.absent(sodium.crypto_sign_verify_detached(sig, test.m.subarray(0, i), pk)) sig.subarray(0, 32).fill(0xff) sig[0] = 0xdb t.absent(sodium.crypto_sign_verify_detached(sig, test.m.subarray(0, i), pk)) sodium.crypto_sign_detached(sig, test.m.subarray(0, i), skpk) hex2bin(pk, '3eee494fb9eac773144e34b0c755affaf33ea782c0722e5ea8b150e61209ab36') t.absent(sodium.crypto_sign_verify_detached(sig, test.m.subarray(0, i), pk)) hex2bin(pk, '0200000000000000000000000000000000000000000000000000000000000000') t.absent(sodium.crypto_sign_verify_detached(sig, test.m.subarray(0, i), pk)) hex2bin(pk, '0500000000000000000000000000000000000000000000000000000000000000') t.absent(sodium.crypto_sign_verify_detached(sig, test.m.subarray(0, i), pk)) const keypair_seed = new Uint8Array([ 0x42, 0x11, 0x51, 0xa4, 0x59, 0xfa, 0xea, 0xde, 0x3d, 0x24, 0x71, 0x15, 0xf9, 0x4a, 0xed, 0xae, 0x42, 0x31, 0x81, 0x24, 0x09, 0x5a, 0xfa, 0xbe, 0x4d, 0x14, 0x51, 0xa5, 0x59, 0xfa, 0xed, 0xee ]) t.execution(() => sodium.crypto_sign_seed_keypair(pk, sk, keypair_seed)) t.execution(() => sodium.crypto_sign_keypair(pk, sk)) t.ok(sodium.crypto_sign_BYTES > 0) t.ok(sodium.crypto_sign_SEEDBYTES > 0) t.ok(sodium.crypto_sign_PUBLICKEYBYTES > 0) t.ok(sodium.crypto_sign_SECRETKEYBYTES > 0) t.is(sodium.crypto_sign_BYTES, 64) t.is(sodium.crypto_sign_SEEDBYTES, 32) t.is(sodium.crypto_sign_PUBLICKEYBYTES, 32) t.is(sodium.crypto_sign_SECRETKEYBYTES, 64) t.end() }) test('ed25519 convert', function (t) { const keypair_seed = new Uint8Array([ 0x42, 0x11, 0x51, 0xa4, 0x59, 0xfa, 0xea, 0xde, 0x3d, 0x24, 0x71, 0x15, 0xf9, 0x4a, 0xed, 0xae, 0x42, 0x31, 0x81, 0x24, 0x09, 0x5a, 0xfa, 0xbe, 0x4d, 0x14, 0x51, 0xa5, 0x59, 0xfa, 0xed, 0xee ]) const ed25519_pk = new Uint8Array(sodium.crypto_sign_PUBLICKEYBYTES) const ed25519_skpk = new Uint8Array(sodium.crypto_sign_SECRETKEYBYTES) const curve25519_pk = new Uint8Array(sodium.crypto_scalarmult_BYTES) const curve25519_pk2 = new Uint8Array(sodium.crypto_scalarmult_BYTES) const curve25519_sk = new Uint8Array(sodium.crypto_scalarmult_BYTES) t.ok(sodium.crypto_sign_SEEDBYTES <= sodium.crypto_hash_sha512_BYTES) sodium.crypto_sign_seed_keypair(ed25519_pk, ed25519_skpk, keypair_seed) sodium.crypto_sign_ed25519_pk_to_curve25519(curve25519_pk, ed25519_pk) sodium.crypto_sign_ed25519_sk_to_curve25519(curve25519_sk, ed25519_skpk) const expected_pk = new Uint8Array([ 0xf1, 0x81, 0x4f, 0x0e, 0x8f, 0xf1, 0x04, 0x3d, 0x8a, 0x44, 0xd2, 0x5b, 0xab, 0xff, 0x3c, 0xed, 0xca, 0xe6, 0xc2, 0x2c, 0x3e, 0xda, 0xa4, 0x8f, 0x85, 0x7a, 0xe7, 0x0d, 0xe2, 0xba, 0xae, 0x50 ]) const expected_sk = new Uint8Array([ 0x80, 0x52, 0x03, 0x03, 0x76, 0xd4, 0x71, 0x12, 0xbe, 0x7f, 0x73, 0xed, 0x7a, 0x01, 0x92, 0x93, 0xdd, 0x12, 0xad, 0x91, 0x0b, 0x65, 0x44, 0x55, 0x79, 0x8b, 0x46, 0x67, 0xd7, 0x3d, 0xe1, 0x66 ]) t.alike(curve25519_pk, expected_pk) t.alike(curve25519_sk, expected_sk) for (let i = 0; i < 500; i++) { sodium.crypto_sign_keypair(ed25519_pk, ed25519_skpk) sodium.crypto_sign_ed25519_pk_to_curve25519(curve25519_pk, ed25519_pk) sodium.crypto_sign_ed25519_sk_to_curve25519(curve25519_sk, ed25519_skpk) sodium.crypto_scalarmult_base(curve25519_pk2, curve25519_sk) if (Buffer.compare(curve25519_pk, curve25519_pk2) !== 0) t.fail() } t.pass('passed all cases') ed25519_pk.fill(0) t.exception(() => { sodium.crypto_sign_ed25519_pk_to_curve25519(curve25519_pk, ed25519_pk) }) t.exception(() => { ed25519_pk[0] = 2 sodium.crypto_sign_ed25519_pk_to_curve25519(curve25519_pk, ed25519_pk) }) t.exception(() => { ed25519_pk[0] = 5 sodium.crypto_sign_ed25519_pk_to_curve25519(curve25519_pk, ed25519_pk) }) t.end() }) function parseTest (t) { return { sk: new Uint8Array(t[0]), pk: new Uint8Array(t[1]), sig: new Uint8Array(t[2]), m: new Uint8Array(t[3]) } } function hex2bin (buf, hex) { for (let i = 0; i < hex.length / 2; i++) { buf[i] = Number('0x' + hex.slice(2 * i, 2 * i + 1)) } }