Skip to content

Commit a449324

Browse files
committed
feat: SignatureEnvelope.verify
1 parent fa6cc3c commit a449324

File tree

3 files changed

+481
-2
lines changed

3 files changed

+481
-2
lines changed

.changeset/slimy-kids-trade.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"ox": patch
3+
---
4+
5+
Added `SignatureEnvelope.verify`.

src/tempo/SignatureEnvelope.test.ts

Lines changed: 298 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
1-
import { Hex, PublicKey, Secp256k1, Signature, WebAuthnP256 } from 'ox'
1+
import {
2+
Address,
3+
Hex,
4+
P256,
5+
PublicKey,
6+
Secp256k1,
7+
Signature,
8+
WebAuthnP256,
9+
WebCryptoP256,
10+
} from 'ox'
211
import { describe, expect, test } from 'vitest'
312
import * as SignatureEnvelope from './SignatureEnvelope.js'
413

@@ -1582,6 +1591,294 @@ describe('validate', () => {
15821591
})
15831592
})
15841593

1594+
describe('verify', () => {
1595+
describe('secp256k1', () => {
1596+
test('behavior: verifies valid signature with publicKey', () => {
1597+
const privateKey = Secp256k1.randomPrivateKey()
1598+
const publicKey = Secp256k1.getPublicKey({ privateKey })
1599+
const payload = '0xdeadbeef' as const
1600+
1601+
const signature = Secp256k1.sign({ payload, privateKey })
1602+
const envelope = SignatureEnvelope.from(signature)
1603+
1604+
expect(
1605+
SignatureEnvelope.verify(envelope, {
1606+
payload,
1607+
publicKey,
1608+
}),
1609+
).toBe(true)
1610+
})
1611+
1612+
test('behavior: verifies valid signature with address', () => {
1613+
const privateKey = Secp256k1.randomPrivateKey()
1614+
const publicKey = Secp256k1.getPublicKey({ privateKey })
1615+
const address = Address.fromPublicKey(publicKey)
1616+
const payload = '0xdeadbeef' as const
1617+
1618+
const signature = Secp256k1.sign({ payload, privateKey })
1619+
const envelope = SignatureEnvelope.from(signature)
1620+
1621+
expect(
1622+
SignatureEnvelope.verify(envelope, {
1623+
payload,
1624+
address,
1625+
}),
1626+
).toBe(true)
1627+
})
1628+
1629+
test('behavior: returns false for wrong publicKey', () => {
1630+
const privateKey = Secp256k1.randomPrivateKey()
1631+
const wrongPrivateKey = Secp256k1.randomPrivateKey()
1632+
const wrongPublicKey = Secp256k1.getPublicKey({
1633+
privateKey: wrongPrivateKey,
1634+
})
1635+
const payload = '0xdeadbeef' as const
1636+
1637+
const signature = Secp256k1.sign({ payload, privateKey })
1638+
const envelope = SignatureEnvelope.from(signature)
1639+
1640+
expect(
1641+
SignatureEnvelope.verify(envelope, {
1642+
payload,
1643+
publicKey: wrongPublicKey,
1644+
}),
1645+
).toBe(false)
1646+
})
1647+
1648+
test('behavior: returns false for wrong payload', () => {
1649+
const privateKey = Secp256k1.randomPrivateKey()
1650+
const publicKey = Secp256k1.getPublicKey({ privateKey })
1651+
const payload = '0xdeadbeef' as const
1652+
1653+
const signature = Secp256k1.sign({ payload, privateKey })
1654+
const envelope = SignatureEnvelope.from(signature)
1655+
1656+
expect(
1657+
SignatureEnvelope.verify(envelope, {
1658+
payload: '0xcafebabe',
1659+
publicKey,
1660+
}),
1661+
).toBe(false)
1662+
})
1663+
})
1664+
1665+
describe('p256', () => {
1666+
test('behavior: verifies valid signature with publicKey', () => {
1667+
const privateKey = P256.randomPrivateKey()
1668+
const publicKey = P256.getPublicKey({ privateKey })
1669+
const payload = '0xdeadbeef' as const
1670+
1671+
const signature = P256.sign({ payload, privateKey })
1672+
const envelope = SignatureEnvelope.from({
1673+
prehash: false,
1674+
publicKey,
1675+
signature,
1676+
})
1677+
1678+
expect(
1679+
SignatureEnvelope.verify(envelope, {
1680+
payload,
1681+
publicKey,
1682+
}),
1683+
).toBe(true)
1684+
})
1685+
1686+
test('behavior: verifies valid signature with address', () => {
1687+
const privateKey = P256.randomPrivateKey()
1688+
const publicKey = P256.getPublicKey({ privateKey })
1689+
const address = Address.fromPublicKey(publicKey)
1690+
const payload = '0xdeadbeef' as const
1691+
1692+
const signature = P256.sign({ payload, privateKey })
1693+
const envelope = SignatureEnvelope.from({
1694+
prehash: false,
1695+
publicKey,
1696+
signature,
1697+
})
1698+
1699+
expect(
1700+
SignatureEnvelope.verify(envelope, {
1701+
payload,
1702+
address,
1703+
}),
1704+
).toBe(true)
1705+
})
1706+
1707+
test('behavior: returns false for mismatched publicKey', () => {
1708+
const privateKey = P256.randomPrivateKey()
1709+
const publicKey = P256.getPublicKey({ privateKey })
1710+
const wrongPrivateKey = P256.randomPrivateKey()
1711+
const wrongPublicKey = P256.getPublicKey({ privateKey: wrongPrivateKey })
1712+
const payload = '0xdeadbeef' as const
1713+
1714+
const signature = P256.sign({ payload, privateKey })
1715+
const envelope = SignatureEnvelope.from({
1716+
prehash: false,
1717+
publicKey,
1718+
signature,
1719+
})
1720+
1721+
expect(
1722+
SignatureEnvelope.verify(envelope, {
1723+
payload,
1724+
publicKey: wrongPublicKey,
1725+
}),
1726+
).toBe(false)
1727+
})
1728+
1729+
test('behavior: returns false for wrong payload', () => {
1730+
const privateKey = P256.randomPrivateKey()
1731+
const publicKey = P256.getPublicKey({ privateKey })
1732+
const payload = '0xdeadbeef' as const
1733+
1734+
const signature = P256.sign({ payload, privateKey })
1735+
const envelope = SignatureEnvelope.from({
1736+
prehash: false,
1737+
publicKey,
1738+
signature,
1739+
})
1740+
1741+
expect(
1742+
SignatureEnvelope.verify(envelope, {
1743+
payload: '0xcafebabe',
1744+
publicKey,
1745+
}),
1746+
).toBe(false)
1747+
})
1748+
})
1749+
1750+
describe('webCryptoP256', () => {
1751+
test('behavior: verifies valid signature with publicKey', async () => {
1752+
const { privateKey, publicKey } = await WebCryptoP256.createKeyPair()
1753+
const payload = '0xdeadbeef' as const
1754+
1755+
const signature = await WebCryptoP256.sign({ payload, privateKey })
1756+
const envelope = SignatureEnvelope.from({
1757+
prehash: true,
1758+
publicKey,
1759+
signature,
1760+
})
1761+
1762+
expect(
1763+
SignatureEnvelope.verify(envelope, {
1764+
payload,
1765+
publicKey,
1766+
}),
1767+
).toBe(true)
1768+
})
1769+
1770+
test('behavior: verifies valid signature with address', async () => {
1771+
const { privateKey, publicKey } = await WebCryptoP256.createKeyPair()
1772+
const address = Address.fromPublicKey(publicKey)
1773+
const payload = '0xdeadbeef' as const
1774+
1775+
const signature = await WebCryptoP256.sign({ payload, privateKey })
1776+
const envelope = SignatureEnvelope.from({
1777+
prehash: true,
1778+
publicKey,
1779+
signature,
1780+
})
1781+
1782+
expect(
1783+
SignatureEnvelope.verify(envelope, {
1784+
payload,
1785+
address,
1786+
}),
1787+
).toBe(true)
1788+
})
1789+
1790+
test('behavior: returns false for mismatched publicKey', async () => {
1791+
const { privateKey, publicKey } = await WebCryptoP256.createKeyPair()
1792+
const { publicKey: wrongPublicKey } = await WebCryptoP256.createKeyPair()
1793+
const payload = '0xdeadbeef' as const
1794+
1795+
const signature = await WebCryptoP256.sign({ payload, privateKey })
1796+
const envelope = SignatureEnvelope.from({
1797+
prehash: true,
1798+
publicKey,
1799+
signature,
1800+
})
1801+
1802+
expect(
1803+
SignatureEnvelope.verify(envelope, {
1804+
payload,
1805+
publicKey: wrongPublicKey,
1806+
}),
1807+
).toBe(false)
1808+
})
1809+
1810+
test('behavior: returns false for wrong payload', async () => {
1811+
const { privateKey, publicKey } = await WebCryptoP256.createKeyPair()
1812+
const payload = '0xdeadbeef' as const
1813+
1814+
const signature = await WebCryptoP256.sign({ payload, privateKey })
1815+
const envelope = SignatureEnvelope.from({
1816+
prehash: true,
1817+
publicKey,
1818+
signature,
1819+
})
1820+
1821+
expect(
1822+
SignatureEnvelope.verify(envelope, {
1823+
payload: '0xcafebabe',
1824+
publicKey,
1825+
}),
1826+
).toBe(false)
1827+
})
1828+
})
1829+
1830+
describe('webAuthn', () => {
1831+
test('behavior: returns false for mismatched publicKey', () => {
1832+
const wrongPrivateKey = P256.randomPrivateKey()
1833+
const wrongPublicKey = P256.getPublicKey({ privateKey: wrongPrivateKey })
1834+
const payload = '0xdeadbeef' as const
1835+
1836+
expect(
1837+
SignatureEnvelope.verify(signature_webauthn, {
1838+
payload,
1839+
publicKey: wrongPublicKey,
1840+
}),
1841+
).toBe(false)
1842+
})
1843+
1844+
test('behavior: returns false for mismatched address', () => {
1845+
const wrongPrivateKey = P256.randomPrivateKey()
1846+
const wrongPublicKey = P256.getPublicKey({ privateKey: wrongPrivateKey })
1847+
const wrongAddress = Address.fromPublicKey(wrongPublicKey)
1848+
const payload = '0xdeadbeef' as const
1849+
1850+
expect(
1851+
SignatureEnvelope.verify(signature_webauthn, {
1852+
payload,
1853+
address: wrongAddress,
1854+
}),
1855+
).toBe(false)
1856+
})
1857+
})
1858+
1859+
describe('keychain', () => {
1860+
test('behavior: returns false for keychain signatures', () => {
1861+
const privateKey = Secp256k1.randomPrivateKey()
1862+
const secp256k1PublicKey = Secp256k1.getPublicKey({ privateKey })
1863+
const payload = '0xdeadbeef' as const
1864+
1865+
const signature = Secp256k1.sign({ payload, privateKey })
1866+
const innerEnvelope = SignatureEnvelope.from(signature)
1867+
const envelope = SignatureEnvelope.from({
1868+
userAddress: '0x1234567890123456789012345678901234567890',
1869+
inner: innerEnvelope,
1870+
})
1871+
1872+
expect(
1873+
SignatureEnvelope.verify(envelope, {
1874+
payload,
1875+
publicKey: secp256k1PublicKey,
1876+
}),
1877+
).toBe(false)
1878+
})
1879+
})
1880+
})
1881+
15851882
describe('fromRpc', () => {
15861883
describe('secp256k1', () => {
15871884
test('behavior: converts RPC secp256k1 signature', () => {

0 commit comments

Comments
 (0)