"bindings": "esm",
"sourceMap": false,
"debug": false,
- "initialMemory": 2,
+ "initialMemory": 4,
"runtime": "stub",
"exportRuntime": false,
"enable": [
*
* - S < 2²⁵³, instead of S < L
* - Skip canonical and small-order checks on public key
- * - Skip checks on r and sb_ah
+ * - Byte-for-byte comparison of `r` to `s`
*
* IMPORTANT: Callers MUST call `crypto_verify_decodepubkey` first in order to
* set `A` for the scalar multiplication step before checking `sB = R + hA`.
ge_double_scalarmult_vartime_to_p3(sb_ah, h, A, S)
ge_p3_tobytes(check_r, sb_ah)
- return equalbytes(s, check_r, KEY_BYTELENGTH) - 1
+ return equalbytes(s, check_r, 32) - 1
}
/**
return ge_has_small_order(check) - 1
// ge_p3_tobytes(check_r, sb_ah)
- // return equalbytes(s, check_r, KEY_BYTELENGTH) - 1
+ // return equalbytes(s, check_r, 32) - 1
}
export const BLOCKHASH_BYTELENGTH: i32 = 32
export const KEY_BYTELENGTH: i32 = 32
-export const MAX_VERIFY_BLOCKS: i32 = 32
-export const MAX_MESSAGE_BYTELENGTH: i32 = 1 << 15
export const SIGNATURE_BYTELENGTH: i32 = 64
-export const SIGNEDBLOCK_BYTELENGTH: i32 = BLOCKHASH_BYTELENGTH + SIGNATURE_BYTELENGTH
+
+const PAGE_BYTELENGTH: i32 = 1 << 16
+const SIGNEDBLOCK_BYTELENGTH: i32 = BLOCKHASH_BYTELENGTH + SIGNATURE_BYTELENGTH
+export const MAX_VERIFY_BLOCKS: i32 = 32
+export const MAX_VERIFY_BLOCKS_BYTELENGTH: i32 = MAX_VERIFY_BLOCKS * SIGNEDBLOCK_BYTELENGTH
+export const MAX_MESSAGE_BYTELENGTH: i32 = MAX_VERIFY_BLOCKS_BYTELENGTH > PAGE_BYTELENGTH ? MAX_VERIFY_BLOCKS_BYTELENGTH : PAGE_BYTELENGTH
// Static I/O buffers
const INPUT_MSG = new StaticArray<u8>(MAX_MESSAGE_BYTELENGTH)
const OUTPUT_SIGN = new StaticArray<u8>(SIGNATURE_BYTELENGTH)
const OUTPUT_VERIFY = new StaticArray<u8>(MAX_VERIFY_BLOCKS)
-/** Returns the pointer to the static message input buffer (32 KiB). */
+/** Returns a pointer to the static message input buffer. */
export function ptrInputMsg (): usize {
return changetype<usize>(INPUT_MSG)
}
-/** Returns the pointer to the static private key input buffer (32 bytes). */
+/** Returns a pointer to the static private key input buffer (32 bytes). */
export function ptrInputPrv (): usize {
return changetype<usize>(INPUT_PRV)
}
-/** Returns the pointer to the static public key input buffer (32 bytes). */
+/** Returns a pointer to the static public key input buffer (32 bytes). */
export function ptrInputPub (): usize {
return changetype<usize>(INPUT_PUB)
}
-/** Returns the pointer to the static signature input buffer (64 bytes). */
+/** Returns a pointer to the static signature input buffer (64 bytes). */
export function ptrInputSig (): usize {
return changetype<usize>(INPUT_SIG)
}
-/** Returns the pointer to the derive() static output buffer (64 bytes). */
+/** Returns a pointer to the derive() static output buffer (64 bytes). */
export function ptrOutputDerive (): usize {
return changetype<usize>(OUTPUT_DERIVE)
}
-/** Returns the pointer to the sign() static output buffer (64 bytes). */
+/** Returns a pointer to the sign() static output buffer (64 bytes). */
export function ptrOutputSign (): usize {
return changetype<usize>(OUTPUT_SIGN)
}
-/** Returns the pointer to the verify() static output buffer (64 bytes). */
+/** Returns a pointer to the verify() static output buffer (64 bytes). */
export function ptrOutputVerify (): usize {
return changetype<usize>(OUTPUT_VERIFY)
}
d &= 255
return u8(((d - 1) >> 8) & 1)
}
+
+/** Unit tests on initialization */
+const testbytesA = new StaticArray<u8>(32).fill(0)
+const testbytesB = new StaticArray<u8>(32).fill(0)
+for (let i = 0; i < 32; i++) {
+ testbytesA[i] = 1
+ if (equalbytes(testbytesA, testbytesB, 32)) {
+ throw new Error('equalbytes failed unit test')
+ }
+ testbytesA[i] = 0
+}
import * as nano25519 from './lib'
+export { constants } from './lib'
+
/**
* Nano public key derivation using WebAssembly.
* @param {Uint8Array<ArrayBuffer>} prv - 32-byte private key
//! SPDX-FileCopyrightText: 2026 Chris Duncan <chris@codecow.com>
//! SPDX-License-Identifier: GPL-3.0-or-later
-import { clear, exports, INPUT_PRV, isBytes, KEY_BYTELENGTH, normalize, OUTPUT_DERIVE } from './wasm'
+import { clear, constants, exports, isBytes, normalize, pointers, } from './wasm'
+
+const { KEY_BYTELENGTH, } = constants
+const { INPUT_PRV, OUTPUT_DERIVE, } = pointers
export function derive (prv: unknown, out?: unknown): string | Uint8Array<ArrayBuffer> | void {
if (typeof out !== 'undefined' && !(isBytes(out) && out.byteLength === KEY_BYTELENGTH)) {
export { derive } from './derive'
export { sign } from './sign'
export { verify, verify_blocks } from './verify'
+export { constants } from './wasm'
//! SPDX-FileCopyrightText: 2026 Chris Duncan <chris@codecow.com>
//! SPDX-License-Identifier: GPL-3.0-or-later
-import { clear, exports, INPUT_MSG, INPUT_PRV, INPUT_PUB, isBytes, KEY_BYTELENGTH, MAX_MESSAGE_BYTELENGTH, normalize, OUTPUT_SIGN, SIGNATURE_BYTELENGTH } from './wasm'
+import { clear, constants, exports, isBytes, normalize, pointers, } from './wasm'
+
+const { KEY_BYTELENGTH, MAX_MESSAGE_BYTELENGTH, SIGNATURE_BYTELENGTH, } = constants
+const { INPUT_MSG, INPUT_PRV, INPUT_PUB, OUTPUT_SIGN, } = pointers
export function sign (msg: unknown, prv: unknown, pub: unknown, out?: unknown): string | Uint8Array<ArrayBuffer> | void {
if (typeof out !== 'undefined' && !(isBytes(out) && out.byteLength === 64)) {
//! SPDX-FileCopyrightText: 2026 Chris Duncan <chris@codecow.com>
//! SPDX-License-Identifier: GPL-3.0-or-later
-import { BLOCKHASH_BYTELENGTH, INPUT_MSG, INPUT_PUB, INPUT_SIG, KEY_BYTELENGTH, MAX_MESSAGE_BYTELENGTH, MAX_VERIFY_BLOCKS, OUTPUT_VERIFY, SIGNATURE_BYTELENGTH, clear, exports, normalize } from './wasm'
+import { clear, constants, exports, normalize, pointers, } from './wasm'
+
+const { BLOCKHASH_BYTELENGTH, KEY_BYTELENGTH, MAX_MESSAGE_BYTELENGTH, MAX_VERIFY_BLOCKS, SIGNATURE_BYTELENGTH, } = constants
+const { INPUT_MSG, INPUT_PUB, INPUT_SIG, OUTPUT_VERIFY, } = pointers
export function verify (sig: unknown, msg: unknown, pub: unknown): boolean {
let buffer = new Uint8Array(exports.memory.buffer)
ptrOutputVerify: () => number
BLOCKHASH_BYTELENGTH: WebAssembly.Global
KEY_BYTELENGTH: WebAssembly.Global
+ SIGNATURE_BYTELENGTH: WebAssembly.Global
MAX_VERIFY_BLOCKS: WebAssembly.Global
+ MAX_VERIFY_BLOCKS_BYTELENGTH: WebAssembly.Global
MAX_MESSAGE_BYTELENGTH: WebAssembly.Global
- SIGNATURE_BYTELENGTH: WebAssembly.Global
- SIGNEDBLOCK_BYTELENGTH: WebAssembly.Global
memory: WebAssembly.Memory
}
}
}
}) as Exports
-export const BLOCKHASH_BYTELENGTH = exports.BLOCKHASH_BYTELENGTH.value
-export const KEY_BYTELENGTH = exports.KEY_BYTELENGTH.value
-export const MAX_MESSAGE_BYTELENGTH = exports.MAX_MESSAGE_BYTELENGTH.value
-export const MAX_VERIFY_BLOCKS = exports.MAX_VERIFY_BLOCKS.value
-export const SIGNATURE_BYTELENGTH = exports.SIGNATURE_BYTELENGTH.value
-export const SIGNEDBLOCK_BYTELENGTH = exports.SIGNEDBLOCK_BYTELENGTH.value
+const BLOCKHASH_BYTELENGTH = exports.BLOCKHASH_BYTELENGTH.value
+const KEY_BYTELENGTH = exports.KEY_BYTELENGTH.value
+const SIGNATURE_BYTELENGTH = exports.SIGNATURE_BYTELENGTH.value
-export const INPUT_MSG = exports.ptrInputMsg()
-export const INPUT_PRV = exports.ptrInputPrv()
-export const INPUT_PUB = exports.ptrInputPub()
-export const INPUT_SIG = exports.ptrInputSig()
-export const OUTPUT_DERIVE = exports.ptrOutputDerive()
-export const OUTPUT_SIGN = exports.ptrOutputSign()
-export const OUTPUT_VERIFY = exports.ptrOutputVerify()
+const MAX_VERIFY_BLOCKS = exports.MAX_VERIFY_BLOCKS.value
+const MAX_VERIFY_BLOCKS_BYTELENGTH = exports.MAX_VERIFY_BLOCKS_BYTELENGTH.value
+const MAX_MESSAGE_BYTELENGTH = exports.MAX_MESSAGE_BYTELENGTH.value
+
+export const constants = {
+ BLOCKHASH_BYTELENGTH,
+ KEY_BYTELENGTH,
+ SIGNATURE_BYTELENGTH,
+ MAX_VERIFY_BLOCKS,
+ MAX_VERIFY_BLOCKS_BYTELENGTH,
+ MAX_MESSAGE_BYTELENGTH
+}
+
+const INPUT_MSG = exports.ptrInputMsg()
+const INPUT_PRV = exports.ptrInputPrv()
+const INPUT_PUB = exports.ptrInputPub()
+const INPUT_SIG = exports.ptrInputSig()
+const OUTPUT_DERIVE = exports.ptrOutputDerive()
+const OUTPUT_SIGN = exports.ptrOutputSign()
+const OUTPUT_VERIFY = exports.ptrOutputVerify()
+
+export const pointers = {
+ INPUT_MSG,
+ INPUT_PRV,
+ INPUT_PUB,
+ INPUT_SIG,
+ OUTPUT_DERIVE,
+ OUTPUT_SIGN,
+ OUTPUT_VERIFY,
+}
export function clear (memory: Uint8Array): void {
memory.fill(0, INPUT_MSG, INPUT_MSG + MAX_MESSAGE_BYTELENGTH)
if (api === 'nano25519 with bulk block verification') {
publicKey = derive(privateKey, 'nano25519')
const blocks = []
- for (let b = 0; blockhash < 32; b++) {
+ for (let b = 0; b < nano25519.constants.MAX_VERIFY_BLOCKS; b++) {
blockHash = random()
signature = sign(blockHash, privateKey, publicKey, 'nano25519')
blocks[b] = { hash: blockHash, signature }
if (verified.some(v => v !== true)) {
throw new Error(`invalid result\nsignature: ${signature}\nblock hash: ${blockHash}\npublic key: ${publicKey}`)
}
- duration = (end - start) / 32
+ duration = (end - start) / nano25519.constants.MAX_VERIFY_BLOCKS
deriveTimes[i].push(0)
signTimes[i].push(0)
verifyTimes[i].push(duration)
//! SPDX-FileCopyrightText: 2026 Chris Duncan <chris@codecow.com>
//! SPDX-License-Identifier: GPL-3.0-or-later
-import { derive, sign, verify, verify_blocks } from 'nano25519'
+import { constants, derive, sign, verify, verify_blocks } from 'nano25519'
import { NANO_ORG_VECTOR, PROBLEM_VECTOR, PYTHON_ED25519_BLAKE2B_VECTORS } from './vectors.mjs'
/**
failures += +!test
try {
- result = sign('1'.repeat(65538), NANO_ORG_VECTOR.privateKey, NANO_ORG_VECTOR.publicKey)
+ result = sign('1'.repeat((constants.MAX_MESSAGE_BYTELENGTH << 1) + 1), NANO_ORG_VECTOR.privateKey, NANO_ORG_VECTOR.publicKey)
result = false
} catch (err) {
+ console.log(err)
if (err != null && typeof err === 'object' && 'message' in err) {
- result = err.message === `Invalid hexadecimal length 65538 for message`
+ result = err.message === `Invalid hexadecimal length ${(constants.MAX_MESSAGE_BYTELENGTH << 1) + 1} for message`
} else {
result = false
}
}
test = result === true
-check(`sign message too long (65538 '1's)`, test)
+check(`sign message too long (${(constants.MAX_MESSAGE_BYTELENGTH << 1) + 1} '1's)`, test)
passes += +test
failures += +!test
failures += +!test
try {
- result = sign(NANO_ORG_VECTOR.blockHash + '0', NANO_ORG_VECTOR.privateKey, NANO_ORG_VECTOR.publicKey)
- result = false
-} catch (err) {
- if (err != null && typeof err === 'object' && 'message' in err) {
- result = err.message === 'Invalid hexadecimal length 65 for message'
- } else {
- result = false
- }
-}
-test = result === true
-check(`sign message odd character count ${NANO_ORG_VECTOR.blockHash + '0'}`, test)
-passes += +test
-failures += +!test
-
-try {
- result = sign('1'.repeat(65538), NANO_ORG_VECTOR.privateKey, NANO_ORG_VECTOR.publicKey)
+ result = sign(new Uint8Array(constants.MAX_MESSAGE_BYTELENGTH + 1).fill(1), NANO_ORG_VECTOR.privateKeyBytes, NANO_ORG_VECTOR.publicKeyBytes)
result = false
} catch (err) {
+ console.log(err)
if (err != null && typeof err === 'object' && 'message' in err) {
- result = err.message === 'Invalid hexadecimal length 65538 for message'
+ result = err.message === `message must be no more than ${constants.MAX_MESSAGE_BYTELENGTH} bytes`
} else {
result = false
}
}
test = result === true
-check(`sign message too long (65538 '1's)`, test)
+check(`sign message too long (${constants.MAX_MESSAGE_BYTELENGTH + 1} bytes)`, test)
passes += +test
failures += +!test
try {
const blocks = []
- for (let i = 0; i < 32; i++) {
+ for (let i = 0; i < constants.MAX_VERIFY_BLOCKS; i++) {
blocks[i] = { hash: NANO_ORG_VECTOR.blockHashBytes, signature: NANO_ORG_VECTOR.signatureBytes }
}
const verified = verify_blocks(NANO_ORG_VECTOR.publicKeyBytes, blocks)
result = false
}
test = result === true
-check(`verify_blocks 32 max`, test)
+check(`verify_blocks ${constants.MAX_VERIFY_BLOCKS} max`, test)
passes += +test
failures += +!test
try {
const blocks = []
- for (let i = 0; i < 33; i++) {
+ for (let i = 0; i < constants.MAX_VERIFY_BLOCKS + 1; i++) {
blocks[i] = { hash: NANO_ORG_VECTOR.blockHashBytes, signature: NANO_ORG_VECTOR.signatureBytes }
}
verify_blocks(NANO_ORG_VECTOR.publicKeyBytes, blocks)
result = false
} catch (err) {
if (err != null && typeof err === 'object' && 'message' in err) {
- result = err.message === 'Bulk Nano block verification must be no more than 32 blocks'
+ result = err.message === `Bulk Nano block verification must be no more than ${constants.MAX_VERIFY_BLOCKS} blocks`
} else {
result = false
}