}
}
- function random(length = 32) {
- const bytes = crypto.getRandomValues(new Uint8Array(length))
+ /** @type { { bytes: Uint8Array, hex: string } } */
+ const rand32 = {
+ get bytes() { return crypto.getRandomValues(new Uint8Array(32)) },
+ get hex() { return b2a(this.bytes) }
+ }
+
+ /** @type { (hex: string) => Uint8Array } */
+ const a2b = (hex) => {
+ return new Uint8Array(hex.match(/.{2}/g).map(b => parseInt(b, 16)))
+ }
+
+ /** @type { (bytes: Uint8Array) => string } */
+ const b2a = (bytes) => {
return [...bytes].map(b => b.toString(16).padStart(2, '0')).join('')
}
+ /**
+ * @param {Uint8Array} prv
+ * @param {string} api
+ * @returns {Uint8Array}
+ */
const derive = (prv, api) => {
- const prv8 = new Uint8Array(prv.match(/.{2}/g).map(b => parseInt(b, 16)))
switch (api) {
- case 'nano25519':
- case 'nano25519 with bulk block verification': {
- const pub8 = nano25519.derive(prv8)
- return [...pub8].map(b => b.toString(16).padStart(2, '0')).join('')
+ case 'nano25519': {
+ return nano25519.derive(prv)
}
case 'NanocurrencyWeb': {
- return NanocurrencyWeb.wallet.legacyAccounts(prv)[0].publicKey
+ const { publicKey } = NanocurrencyWeb.wallet.legacyAccounts(b2a(prv))[0]
+ return a2b(publicKey)
}
case 'Sodium': {
- return sodium.crypto_sign_seed_keypair(prv8, 'hex').publicKey
+ return sodium.crypto_sign_seed_keypair(prv).publicKey
}
case 'TweetNaCl.js': {
- const pub8 = nacl.sign.keyPair.fromSeed(prv8).publicKey
- return [...pub8].map(b => b.toString(16).padStart(2, '0')).join('')
+ return nacl.sign.keyPair.fromSeed(prv).publicKey
}
default: {
return null
}
}
+ /**
+ * @param {Uint8Array} msg
+ * @param {Uint8Array} prv
+ * @param {Uint8Array} pub
+ * @param {string} api
+ * @returns {Uint8Array}
+ */
const sign = (msg, prv, pub, api) => {
- const msg8 = new Uint8Array(msg.match(/.{2}/g).map(b => parseInt(b, 16)))
- const prv8 = new Uint8Array(prv.match(/.{2}/g).map(b => parseInt(b, 16)))
- const pub8 = new Uint8Array(pub.match(/.{2}/g).map(b => parseInt(b, 16)))
- const sk8 = new Uint8Array((prv + pub).match(/.{2}/g).map(b => parseInt(b, 16)))
+ const sk = new Uint8Array([...prv, ...pub])
switch (api) {
case 'nano25519':
case 'nano25519 with bulk block verification': {
- const sig8 = nano25519.sign(msg8, prv8, pub8)
- return [...sig8].map(b => b.toString(16).padStart(2, '0')).join('')
+ return nano25519.sign(msg, prv, pub)
}
case 'NanocurrencyWeb': {
- const { privateKey } = NanocurrencyWeb.wallet.legacyAccounts(prv)[0]
- return NanocurrencyWeb.tools.sign(privateKey, msg)
+ const { privateKey } = NanocurrencyWeb.wallet.legacyAccounts(b2a(prv))[0]
+ const sig = NanocurrencyWeb.tools.sign(privateKey, b2a(msg))
+ return a2b(sig)
}
case 'Sodium': {
- return sodium.crypto_sign_detached(new Uint8Array(msg8), new Uint8Array(sk8), 'hex')
+ return sodium.crypto_sign_detached(msg, sk)
}
case 'TweetNaCl.js': {
- const sig8 = nacl.sign.detached(new Uint8Array(msg8), new Uint8Array(sk8))
- return [...sig8].map(b => b.toString(16).padStart(2, '0')).join('')
+ return nacl.sign.detached(msg, sk)
}
default: {
return null
}
}
+ /**
+ * @param {Uint8Array} sig
+ * @param {Uint8Array} msg
+ * @param {Uint8Array} pub
+ * @param {string} api
+ * @returns {boolean}
+ */
const verify = (sig, msg, pub, api) => {
- const msg8 = new Uint8Array(msg.match(/.{2}/g).map(b => parseInt(b, 16)))
- const sig8 = new Uint8Array(sig.match(/.{2}/g).map(b => parseInt(b, 16)))
- const pub8 = new Uint8Array(pub.match(/.{2}/g).map(b => parseInt(b, 16)))
switch (api) {
case 'nano25519': {
- return nano25519.verify(sig8, msg8, pub8)
+ return nano25519.verify(sig, msg, pub)
}
case 'NanocurrencyWeb': {
- return NanocurrencyWeb.tools.verify(pub, sig, msg)
+ return NanocurrencyWeb.tools.verify(b2a(pub), b2a(sig), b2a(msg))
}
case 'Sodium': {
- return sodium.crypto_sign_verify_detached(sig8, msg8, pub8)
+ return sodium.crypto_sign_verify_detached(sig, msg, pub)
}
case 'TweetNaCl.js': {
- return nacl.sign.detached.verify(msg8, sig8, pub8)
+ return nacl.sign.detached.verify(msg, sig, pub)
}
default: {
return null
}
}
+ /**
+ * @param {string} api
+ * @param {number} size
+ * @param {number} runs
+ * @returns {void}
+ */
export async function test(api, size, runs) {
if (typeof size !== 'number' || size < 1) {
size = 1
/**
* @param {string} name
* @param {boolean} test
+ * @returns {void}
*/
function check(name, test) {
if (typeof test !== 'boolean') {
passes += +test
failures += +!test
- result = nano25519.verify(NANO_ORG_VECTOR.signature, random(), NANO_ORG_VECTOR.publicKey)
+ result = nano25519.verify(NANO_ORG_VECTOR.signature, rand32.hex, NANO_ORG_VECTOR.publicKey)
console.log(result)
test = result === false
check(`verify() output for random block hash`, test)
for (let j = 0; j < size; j++) {
document.getElementById('status').innerHTML = `TESTING IN PROGRESS. THIS MAY TAKE A LONG TIME. ${i}/${runs} ${j}/${size}<br/>`
- let start, end, duration, blockhash, privateKey, publicKey, signature
+ let start, end, duration, message, privateKey, publicKey, signature
start = end = duration = 0
- privateKey = random()
try {
if (api === 'nano25519 with bulk block verification') {
+ privateKey = rand32.bytes
publicKey = derive(privateKey, 'nano25519')
const blocks = []
for (let b = 0; b < nano25519.constants.MAX_VERIFY_BLOCKS; b++) {
- blockHash = random()
- signature = sign(blockHash, privateKey, publicKey, 'nano25519')
- blocks[b] = { hash: blockHash, signature }
+ message = rand32.bytes
+ signature = sign(message, privateKey, publicKey, 'nano25519')
+ blocks[b] = { hash: message, signature }
}
start = performance.now()
const verified = nano25519.verify_blocks(publicKey, blocks)
signTimes[i].push(0)
verifyTimes[i].push(duration)
} else {
- blockHash = random()
+ privateKey = rand32.bytes
+ message = rand32.bytes
start = performance.now()
publicKey = derive(privateKey, api)
deriveTimes[i].push(duration)
start = performance.now()
- signature = sign(blockHash, privateKey, publicKey, api)
+ signature = sign(message, privateKey, publicKey, api)
end = performance.now()
duration = end - start
signTimes[i].push(duration)
start = performance.now()
- if (!verify(signature, blockHash, publicKey, api)) {
- throw new Error(`invalid result\nsignature: ${signature}\nblock hash: ${blockHash}\npublic key: ${publicKey}`)
+ if (!verify(signature, message, publicKey, api)) {
+ throw new Error(`invalid result\nsignature: ${signature}\nblock hash: ${message}\npublic key: ${publicKey}`)
}
end = performance.now()
duration = end - start