*
* Call `crypto_verify_decodepubkey` first in order to get decode the public key
* to `A` for the scalar multiplication step before checking `sB = R + hA`.
- * @returns -1 if signature fails to verify, else return 0 if signature is good
+ * @returns 0 if signature fails to verify, else return 1 if signature is good
*/
export function crypto_verify_donna (sig: StaticArray<u8>, M: StaticArray<u8>, A: ge_p3, pub: StaticArray<u8>): i32 {
// fail if private scalar `S` is out of range (`2²⁵³ ≤ S`)
- if ((sig[63] & 224) != 0) return -1
+ if ((sig[63] & 224) != 0) return 0
memory.copy(changetype<usize>(S), changetype<usize>(sig) + 32, 32)
ge_double_scalarmult_vartime_to_p3(sb_ah, h, A, S)
ge_p3_tobytes(check_r, sb_ah)
- return equalbytes(sig, check_r, KEY_BYTELENGTH) - 1
+ return equalbytes(sig, check_r, KEY_BYTELENGTH)
}
/**
*
* Unlike `crypto_verify_donna`, this function is intended for single-use
* verifications and thus can compute and set `A` itself.
- * @returns -1 if signature fails to verify, else return 0 if signature is good
+ * @returns 0 if signature fails to verify, else return 1 if signature is good
*/
export function crypto_verify_sodium (sig: StaticArray<u8>, M: StaticArray<u8>, mlen: i32, pub: StaticArray<u8>): i32 {
// fail if public key `k` is non-canonical (`p = 2²⁵⁵-19 ≤ k`)
- if (!ge_is_canonical(pub)) return -1
+ if (!ge_is_canonical(pub)) return 0
// fail if public key cannot be decoded
- if (ge_frombytes_negate_vartime(A, pub) != 0) return -1
+ if (ge_frombytes_negate_vartime(A, pub) != 0) return 0
// fail if public key `k` is small order
- if (ge_has_small_order(A) != 0) return -1
+ if (ge_has_small_order(A) != 0) return 0
// fail if private scalar `S` is non-canonical (`L ≤ S`)
memory.copy(changetype<usize>(S), changetype<usize>(sig) + 32, 32)
- if (!sc_is_canonical(S)) return -1
+ if (!sc_is_canonical(S)) return 0
- if (ge_frombytes(expected_r, sig) != 0) return -1
- if (ge_has_small_order(expected_r) != 0) return -1
+ if (ge_frombytes(expected_r, sig) != 0) return 0
+ if (ge_has_small_order(expected_r) != 0) return 0
// signature is nonce point R and scalar S (R || S)
// data to hash is nonce point R, public key A, and message M
ge_double_scalarmult_vartime_to_p3(sb_ah, h, A, S)
ge_sub_p3(check, expected_r, sb_ah)
- return ge_has_small_order(check) - 1
+ return ge_has_small_order(check)
// ge_p3_tobytes(check_r, sb_ah)
// return equalbytes(s, check_r, 32) - 1
const OUTPUT_DERIVE = new StaticArray<u8>(KEY_BYTELENGTH)
const OUTPUT_SIGN = new StaticArray<u8>(SIGNATURE_BYTELENGTH)
-const OUTPUT_VERIFY = new StaticArray<u8>(MAX_VERIFY_BLOCKS).fill(255)
+const OUTPUT_VERIFY = new StaticArray<u8>(MAX_VERIFY_BLOCKS)
/** Returns a pointer to the static message input buffer. */
export function ptrInputMsg (): usize {
* @returns {boolean} True if message was signed by public key's private key
*/
export function verify (mlen: i32): void {
- // Set all output to false so errors fail closed
- OUTPUT_VERIFY.fill(255)
+ // Clear output buffer so errors do not retain stale prior data
+ OUTPUT_VERIFY.fill(0)
// Clear local buffers
pub.fill(0)
* @param {i32} count Number of signatures to verify, up to 64
*/
export function verify_blocks (count: i32): void {
- // Set all output to false so errors fail closed
- OUTPUT_VERIFY.fill(255)
+ // Clear output buffer so errors do not retain stale prior data
+ OUTPUT_VERIFY.fill(0)
// Clear local buffers
h.fill(0)
export { constants } from './lib'
/**
- * Nano public key derivation using WebAssembly.
- * @param {Uint8Array<ArrayBuffer>} prv - 32-byte private key
+ * Nano public key derivation using WebAssembly. If byte output is required,
+ * pass a target buffer as a second argument.
+ * @param {(Uint8Array<ArrayBuffer> | string)} prv - 32-byte private key
* @returns 32-byte public key
*/
-export function derive (prv: Uint8Array<ArrayBuffer>): Uint8Array<ArrayBuffer>
-/**
- * Nano public key derivation using WebAssembly.
- * @param {string} prv - 64-character hexadecimal private key
- * @returns 64-character hexadecimal public key
- */
-export function derive (prv: string): string
+export function derive (prv: Uint8Array<ArrayBuffer> | string): string
/**
* Nano public key derivation using WebAssembly. Instead of allocating an output
* buffer internally for the return value, public key bytes are written to the
* the user-supplied output buffer.
- * @param {Uint8Array<ArrayBuffer>} prv - 32-byte private key
+ * @param {(Uint8Array<ArrayBuffer> | string)} prv - 32-byte private key
* @param {Uint8Array<ArrayBuffer>} out - buffer to receive 32-byte public key
*/
-export function derive (prv: Uint8Array<ArrayBuffer>, out: Uint8Array<ArrayBuffer>): void
-export function derive (prv: string | Uint8Array<ArrayBuffer>, out?: Uint8Array<ArrayBuffer>): string | Uint8Array<ArrayBuffer> | void {
+export function derive (prv: Uint8Array<ArrayBuffer> | string, out: Uint8Array<ArrayBuffer>): void
+export function derive (prv: Uint8Array<ArrayBuffer> | string, out?: Uint8Array<ArrayBuffer>): string | void {
return nano25519.derive(prv, out)
}
/**
* Signing using WebAssembly. To sign Nano blocks, the message should be a
* 32-byte block hash.
- * @param {Uint8Array<ArrayBuffer>} msg - Variable-byte-length message up to 64 KiB
- * @param {Uint8Array<ArrayBuffer>} prv - 32-byte private key
- * @param {Uint8Array<ArrayBuffer>} pub - 32-byte public key
+ * @param {(Uint8Array<ArrayBuffer> | string)} msg - Variable-byte-length message up to 64 KiB
+ * @param {(Uint8Array<ArrayBuffer> | string)} prv - 32-byte private key
+ * @param {(Uint8Array<ArrayBuffer> | string)} pub - 32-byte public key
* @returns 64-byte detached signature
*/
-export function sign (msg: Uint8Array<ArrayBuffer>, prv: Uint8Array<ArrayBuffer>, pub: Uint8Array<ArrayBuffer>): Uint8Array<ArrayBuffer>
-/**
- * Signing using WebAssembly. To sign Nano blocks, the message should be a
- * 64-character hexadecimal block hash.
- * @param {string} msg - Variable-length hexadecimal message up to 64 KiB
- * @param {string} prv - 64-character hexadecimal private key
- * @param {string} pub - 64-character hexadecimal public key
- * @returns 128-character hexadecimal detached signature
- */
-export function sign (msg: string, prv: string, pub: string): string
+export function sign (msg: Uint8Array<ArrayBuffer> | string, prv: Uint8Array<ArrayBuffer> | string, pub: Uint8Array<ArrayBuffer> | string): string
/**
* Signing using WebAssembly. To sign Nano blocks, the message should be a
* 32-byte block hash. Instead of allocating an output buffer internally for the
* return value, signature bytes are written to the the user-supplied output
* buffer.
- * @param {Uint8Array<ArrayBuffer>} msg - Variable-byte-length message up to 64 KiB
- * @param {Uint8Array<ArrayBuffer>} prv - 32-byte private key
- * @param {Uint8Array<ArrayBuffer>} pub - 32-byte public key
- * @param {Uint8Array<ArrayBuffer>} out - buffer to receive 64-byte detached signature
+ * @param {(Uint8Array<ArrayBuffer> | string)} msg - Variable-byte-length message up to 64 KiB
+ * @param {(Uint8Array<ArrayBuffer> | string)} prv - 32-byte private key
+ * @param {(Uint8Array<ArrayBuffer> | string)} pub - 32-byte public key
+ * @param {(Uint8Array<ArrayBuffer> | string)} out - buffer to receive 64-byte detached signature
*/
-export function sign (msg: Uint8Array<ArrayBuffer>, prv: Uint8Array<ArrayBuffer>, pub: Uint8Array<ArrayBuffer>, out: Uint8Array<ArrayBuffer>): void
-export function sign (msg: string | Uint8Array<ArrayBuffer>, prv: string | Uint8Array<ArrayBuffer>, pub: string | Uint8Array<ArrayBuffer>, out?: Uint8Array<ArrayBuffer>): string | Uint8Array<ArrayBuffer> | void {
+export function sign (msg: Uint8Array<ArrayBuffer> | string, prv: Uint8Array<ArrayBuffer> | string, pub: Uint8Array<ArrayBuffer> | string, out: Uint8Array<ArrayBuffer>): void
+export function sign (msg: Uint8Array<ArrayBuffer> | string, prv: Uint8Array<ArrayBuffer> | string, pub: Uint8Array<ArrayBuffer> | string, out?: Uint8Array<ArrayBuffer>): string | void {
return nano25519.sign(msg, prv, pub, out)
}
/**
* Signature verification using WebAssembly. To verify Nano block signatures,
* use `verify_blocks()` instead.
- * @param {Uint8Array<ArrayBuffer>} sig - 64-byte detached signature
- * @param {Uint8Array<ArrayBuffer>} msg - Variable-byte-length message up to 64 KiB
- * @param {Uint8Array<ArrayBuffer>} pub - 32-byte public key
- * @returns true if signature matches block hash and public key, else false
- */
-export function verify (sig: Uint8Array<ArrayBuffer>, msg: Uint8Array<ArrayBuffer>, pub: Uint8Array<ArrayBuffer>): boolean
-/**
- * Signature verification using WebAssembly. To verify Nano block signatures,
- * the message should be a 64-character block hash.
- * @param {string} sig - 128-character hexadecimal detached signature
- * @param {string} msg - Variable-length message up to 64 KiB
- * @param {string} pub - 64-character hexadecimal public key
+ * @param {(Uint8Array<ArrayBuffer> | string)} sig - 64-byte detached signature
+ * @param {(Uint8Array<ArrayBuffer> | string)} msg - Variable-byte-length message up to 64 KiB
+ * @param {(Uint8Array<ArrayBuffer> | string)} pub - 32-byte public key
* @returns true if signature matches block hash and public key, else false
*/
-export function verify (sig: string, msg: string, pub: string): boolean
-export function verify (sig: string | Uint8Array<ArrayBuffer>, msg: string | Uint8Array<ArrayBuffer>, pub: string | Uint8Array<ArrayBuffer>): boolean {
+export function verify (sig: Uint8Array<ArrayBuffer> | string, msg: Uint8Array<ArrayBuffer> | string, pub: Uint8Array<ArrayBuffer> | string): boolean {
return nano25519.verify(sig, msg, pub)
}
/**
* Nano block signature bulk verification using WebAssembly.
- * @param {Uint8Array<ArrayBuffer>} publicKey - 32-byte public key
- * @param {object[]} blocks - Array of up to 64 block signature/hash pairs
- * @param {Uint8Array<ArrayBuffer>} blocks.signature - 64-byte block signature
- * @param {Uint8Array<ArrayBuffer>} blocks.hash - 32-byte block hash
- * @returns Array of results with, for each case, true if signature matches block hash and public key, else false
- */
-export function verify_blocks (publicKey: Uint8Array<ArrayBuffer>, blocks: { hash: Uint8Array<ArrayBuffer>, signature: Uint8Array<ArrayBuffer> }[]): boolean[]
-/**
- * Nano block signature bulk verification using WebAssembly.
- * @param {string} publicKey - 64-character hexadecimal public key
+ * @param {(Uint8Array<ArrayBuffer> | string)} publicKey - 32-byte public key
* @param {object[]} blocks - Array of up to 64 block signature/hash pairs
- * @param {string} blocks.signature - 128-character hexadecimal block signature
- * @param {string} blocks.hash - 64-character hexadecimal block hash
+ * @param {(Uint8Array<ArrayBuffer> | string)} blocks.signature - 64-byte block signature
+ * @param {(Uint8Array<ArrayBuffer> | string)} blocks.hash - 32-byte block hash
* @returns Array of results with, for each case, true if signature matches block hash and public key, else false
*/
-export function verify_blocks (publicKey: string, blocks: { signature: string, hash: string }[]): boolean[]
-export function verify_blocks (publicKey: string | Uint8Array<ArrayBuffer>, blocks: { signature: string | Uint8Array<ArrayBuffer>, hash: string | Uint8Array<ArrayBuffer> }[]): boolean[] {
+export function verify_blocks (publicKey: Uint8Array<ArrayBuffer> | string, blocks: { signature: Uint8Array<ArrayBuffer> | string, hash: Uint8Array<ArrayBuffer> | string }[]): boolean[] {
return nano25519.verify_blocks(publicKey, blocks)
}
const { KEY_BYTELENGTH, } = constants
-export function derive (prv: unknown, out?: unknown): string | Uint8Array<ArrayBuffer> | void {
+export function derive (prv: unknown, out?: unknown): string | void {
if (typeof out !== 'undefined' && !(isBytes(out) && out.byteLength === KEY_BYTELENGTH)) {
throw new TypeError('Derive output buffer must be 32-byte Uint8Array<ArrayBuffer>')
}
for (let i = 0; i < KEY_BYTELENGTH; i++) {
publicKey[i] = buffer[Pointers.OUTPUT_DERIVE + i]
}
- if (typeof prv === 'string') {
+ if (out != null) {
+ out.set(publicKey)
+ return void 0
+ } else {
let hex = ''
for (const byte of publicKey) {
hex += byte.toString(16).padStart(2, '0')
}
return hex
- } else if (isBytes(prv) && out != null) {
- out.set(publicKey)
- publicKey.fill(0)
- return
- } else {
- return publicKey
}
} finally {
privateKey.fill(0)
+ publicKey.fill(0)
clearMemory()
}
}
const { KEY_BYTELENGTH, MAX_MESSAGE_BYTELENGTH, SIGNATURE_BYTELENGTH, } = constants
-export function sign (msg: unknown, prv: unknown, pub: unknown, out?: unknown): string | Uint8Array<ArrayBuffer> | void {
+export function sign (msg: unknown, prv: unknown, pub: unknown, out?: unknown): string | void {
if (typeof out !== 'undefined' && !(isBytes(out) && out.byteLength === SIGNATURE_BYTELENGTH)) {
throw new TypeError(`Sign output buffer must be ${SIGNATURE_BYTELENGTH}-byte Uint8Array<ArrayBuffer>`)
}
for (let i = 0; i < SIGNATURE_BYTELENGTH; i++) {
signature[i] = buffer[Pointers.OUTPUT_SIGN + i]
}
- if (typeof prv === 'string') {
+ if (out != null) {
+ out.set(signature)
+ return void 0
+ } else {
let hex = ''
for (const byte of signature) {
hex += byte.toString(16).padStart(2, '0')
}
return hex
- } else if (isBytes(prv) && out != null) {
- out.set(signature)
- signature.fill(0)
- return
- } else {
- return signature
}
} finally {
privateKey.fill(0)
publicKey.fill(0)
+ signature.fill(0)
clearMemory()
}
}
throw new Nano25519TypeError('WASM memory buffer detached')
}
const verified = buffer[Pointers.OUTPUT_VERIFY]
- return verified === 0
+ return verified === 1
} finally {
clearMemory()
}
for (let i = 0; i < count; i++) {
verified[i] = buffer[Pointers.OUTPUT_VERIFY + i]
}
- return [...verified].map(v => v === 0)
+ return [...verified].map(v => v === 1)
} finally {
clearMemory()
}
// Check byte inputs
result = derive(NANO_ORG_VECTOR.privateKeyBytes)
-test = [...result].map(b => b.toString(16).padStart(2, '0')).join('').toLowerCase() === NANO_ORG_VECTOR.publicKey.toLowerCase()
+test = result.toLowerCase() === NANO_ORG_VECTOR.publicKey.toLowerCase()
check(`derive from private key bytes ${NANO_ORG_VECTOR.privateKey}`, test)
passes += +test
failures += +!test
+outbuf = new Uint8Array(32)
+derive(NANO_ORG_VECTOR.privateKeyBytes, outbuf)
+test = [...outbuf].map(b => b.toString(16).padStart(2, '0')).join('').toLowerCase() === NANO_ORG_VECTOR.publicKey.toLowerCase()
+check(`derive from private key bytes to output buffer`, test)
+passes += +test
+failures += +!test
+
result = sign(NANO_ORG_VECTOR.blockHashBytes, NANO_ORG_VECTOR.privateKeyBytes, NANO_ORG_VECTOR.publicKeyBytes)
-test = [...result].map(b => b.toString(16).padStart(2, '0')).join('').toLowerCase() === NANO_ORG_VECTOR.signature.toLowerCase()
+test = result.toLowerCase() === NANO_ORG_VECTOR.signature.toLowerCase()
check(`sign message bytes ${NANO_ORG_VECTOR.blockHash}`, test)
passes += +test
failures += +!test
const signatureBytes = new Uint8Array(signature.match(/.{2}/g)?.slice(0, 64).map(b => parseInt(b, 16)) ?? [])
result = derive(privateKeyBytes)
- test = [...result].map(b => b.toString(16).padStart(2, '0')).join('').toLowerCase() === publicKey
+ test = result.toLowerCase() === publicKey
check(`derive from private key bytes ${privateKey}`, test)
passes += +test
failures += +!test
result = sign(messageBytes, privateKeyBytes, publicKeyBytes)
- test = [...result].map(b => b.toString(16).padStart(2, '0')).join('').toLowerCase() === signature.slice(0, 128)
+ test = result.toLowerCase() === signature.slice(0, 128)
check(`sign message bytes length ${messageBytes.byteLength}`, test)
passes += +test
failures += +!test