ox
Version:
Ethereum Standard Library
95 lines (84 loc) • 2.8 kB
text/typescript
import { bench, describe } from 'vp/test'
import * as Bytes from '../core/Bytes.js'
import * as Hash from '../core/Hash.js'
import * as Hex from '../core/Hex.js'
import * as P256 from '../core/P256.js'
import * as Authentication from './Authentication.js'
import * as Authenticator from './Authenticator.js'
// Bench-only window stub. Set before module-level fixture construction so
// helpers that read `window.location.hostname` do not throw at import time.
;(globalThis as { window?: unknown }).window ??= {
location: { hostname: 'example.com' },
document: { title: 'Example' },
}
const challenge =
'0xf631058a3ba1116acce12396fad0a125b5041c43f8e15723709f81aa8d5f4ccf'
const { publicKey, privateKey } = P256.createKeyPair()
const authenticatorData = Authenticator.getAuthenticatorData({
rpId: 'example.com',
signCount: 0,
})
const clientDataJSON = Authenticator.getClientDataJSON({
challenge,
origin: 'https://example.com',
})
const clientDataJSONBytes = Bytes.fromString(clientDataJSON)
// Build a signed payload for verify benches
const clientDataJSONHash = Hash.sha256(clientDataJSONBytes, { as: 'Bytes' })
const payloadBytes = Bytes.concat(
Bytes.fromHex(authenticatorData),
clientDataJSONHash,
)
const signature = P256.sign({
hash: true,
payload: payloadBytes,
privateKey,
})
// Minimal ASN.1 DER encoding of the ECDSA signature for the sign-mock response.
const derSignature = (() => {
const toDer = (n: bigint) => {
let h = n.toString(16)
if (h.length % 2) h = `0${h}`
let bytes = Bytes.fromHex(`0x${h}`)
if (bytes[0]! & 0x80) bytes = Bytes.concat(new Uint8Array([0]), bytes)
return bytes
}
const rB = toDer(Hex.toBigInt(signature.r))
const sB = toDer(Hex.toBigInt(signature.s))
const rTlv = Bytes.concat(new Uint8Array([0x02, rB.length]), rB)
const sTlv = Bytes.concat(new Uint8Array([0x02, sB.length]), sB)
const inner = Bytes.concat(rTlv, sTlv)
return Bytes.concat(new Uint8Array([0x30, inner.length]), inner)
})()
const signMockResponse = {
id: 'creds',
response: {
authenticatorData: Bytes.fromHex(authenticatorData),
clientDataJSON: clientDataJSONBytes,
signature: derSignature,
},
} as never
describe('Authentication.sign (mock)', () => {
bench('default', async () => {
await Authentication.sign({
getFn: () => Promise.resolve(signMockResponse),
challenge,
})
})
})
const signResponse = await Authentication.sign({
getFn: () => Promise.resolve(signMockResponse),
challenge,
})
describe('Authentication.verify', () => {
bench('default', () => {
Authentication.verify({
challenge,
metadata: signResponse.metadata,
origin: 'https://example.com',
publicKey,
rpId: 'example.com',
signature: signResponse.signature,
})
})
})