Skip to content

Commit

Permalink
feat: sr25519 (#14)
Browse files Browse the repository at this point in the history
  • Loading branch information
tjjfvi authored Jun 13, 2023
1 parent 322f66e commit a96745c
Show file tree
Hide file tree
Showing 35 changed files with 2,025 additions and 28 deletions.
11 changes: 7 additions & 4 deletions _tasks/build.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import * as flags from "https://deno.land/[email protected]/flags/mod.ts"
import * as path from "https://deno.land/[email protected]/path/mod.ts"
import { assertEquals } from "https://deno.land/[email protected]/testing/asserts.ts"
import { encodeHex } from "../util.ts"
import { encodeHex } from "../common/hex.ts"

const { check } = flags.parse(Deno.args, { boolean: ["check"] })

const wasmPaths = [
"hashers/xxhash",
"hashers/blake2b",
"xxhash/xxhash",
"blake2b/blake2b",
"sr25519/keccak",
"sr25519/ristretto",
"sr25519/sr25519",
]

let success = true
Expand Down Expand Up @@ -36,7 +39,7 @@ async function build(wasmPath: string) {
const content = `
// @generated
import { decodeHex } from "${path.relative(path.dirname(wasmPath), "util.ts")}"
import { decodeHex } from "${path.relative(path.dirname(wasmPath), "common/hex.ts")}"
export default decodeHex(\n"${encodeHex(wasm).replace(/.{0,64}|$/g, "\\\n$&")}",\n)
`.trimStart()
Expand Down
File renamed without changes.
4 changes: 2 additions & 2 deletions hashers/bench/blake2b.bench.ts → blake2b/blake2b.bench.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as refImpl from "https://esm.sh/@noble/[email protected]/blake2b"
import { Blake2b } from "../blake2b.ts"
import { benchHasher } from "./bench_util.ts"
import { benchHasher } from "../bench_util.ts"
import { Blake2b } from "./blake2b.ts"

benchHasher({
name: "blake2b",
Expand Down
4 changes: 2 additions & 2 deletions hashers/test/blake2b.test.ts → blake2b/blake2b.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as refImpl from "https://esm.sh/@noble/[email protected]/blake2b"
import { Blake2b } from "../blake2b.ts"
import { testHasher } from "./test_util.ts"
import { testHasher } from "../common/test_util.ts"
import { Blake2b } from "./blake2b.ts"

for (const size of [512, 8, 16, 32, 64, 128, 256] as const) {
testHasher({
Expand Down
2 changes: 1 addition & 1 deletion hashers/blake2b.ts → blake2b/blake2b.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Hasher } from "../common/hasher.ts"
import wasmCode from "./blake2b.wasm.ts"
import { Hasher } from "./common.ts"

const memory = new WebAssembly.Memory({ initial: 1, maximum: 128 })

Expand Down
2 changes: 1 addition & 1 deletion hashers/blake2b.wasm.ts → blake2b/blake2b.wasm.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @generated

import { decodeHex } from "../util.ts"
import { decodeHex } from "../common/hex.ts"

export default decodeHex(
"\
Expand Down
File renamed without changes.
1 change: 1 addition & 0 deletions blake2b/mod.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./blake2b.ts"
4 changes: 2 additions & 2 deletions hashers/bench/bench_util.ts → common/bench_util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import { DigestAlgorithm } from "https://deno.land/[email protected]/crypto/_wasm/mod.ts"
import { crypto } from "https://deno.land/[email protected]/crypto/mod.ts"
import { Hasher } from "../common.ts"
import { testCases } from "../test/test_util.ts"
import { Hasher } from "./hasher.ts"
import { testCases } from "./test_util.ts"

interface BenchHasherProps {
name: string
Expand Down
File renamed without changes.
File renamed without changes.
17 changes: 17 additions & 0 deletions common/log.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const u64 = (1n << 64n) - 1n
export const log = {
u32: (x: number) => console.log(fmtInt(x >>> 0, 32), x >>> 0),
u64: (x: bigint) => console.log(fmtInt(x & u64, 64), x & u64),
i32: (x: number) => console.log(fmtInt(x >>> 0, 32), x),
i64: (x: bigint) => console.log(fmtInt(x & u64, 64), x),
brk: () => console.log(),
}

export function fmtInt(x: number | bigint, bits: number) {
return x
.toString(16)
.padStart(bits / 4, "0")
.split(/(?=(?:..)+$)/)
.reverse()
.join("")
}
6 changes: 3 additions & 3 deletions hashers/test/test_util.ts → common/test_util.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { assertEquals } from "https://deno.land/[email protected]/testing/asserts.ts"
import { assertSnapshot } from "https://deno.land/[email protected]/testing/snapshot.ts"
import { encodeHex } from "../../util.ts"
import { Hasher } from "../common.ts"
import { Hasher } from "./hasher.ts"
import { encodeHex } from "./hex.ts"

interface TestHasherProps {
name: string
Expand All @@ -13,7 +13,7 @@ const lorem =
// cspell:disable-next-line
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."

const license = await fetch(new URL("../../LICENSE", import.meta.url)).then((r) => r.arrayBuffer())
const license = await fetch(new URL("../LICENSE", import.meta.url)).then((r) => r.arrayBuffer())

export const testCases: [name: string, data: Uint8Array][] = [
["empty", new Uint8Array()],
Expand Down
3 changes: 2 additions & 1 deletion deno.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,6 @@
"bench": "deno task build && deno bench -A --no-check=remote --unstable",
"star": "deno task run _tasks/star.ts && deno cache --no-check=remote target/star.ts; deno task build",
"moderate": "deno task run https://deno.land/x/[email protected]/mod.ts && dprint fmt"
}
},
"lock": false
}
5 changes: 0 additions & 5 deletions hashers/mod.ts

This file was deleted.

4 changes: 3 additions & 1 deletion mod.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// moderate --exclude util.ts

export * from "./hashers/mod.ts"
export * from "./blake2b/mod.ts"
export * from "./sr25519/mod.ts"
export * from "./xxhash/mod.ts"
154 changes: 154 additions & 0 deletions sr25519/arithmetic.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
import { assertEquals } from "https://deno.land/[email protected]/testing/asserts.ts"
import { instantiate } from "./sr25519.ts"

const { field, fieldI, scalar, mem, readU256, u256, u512, wasm, writeU256 } = instantiate()

const u256s = [
0n,
1n,
2n,
(1n << 32n) - 1n,
1n << 32n,
1n << 128n,
u256 - 1n,
field - 1n,
scalar - 1n,
field,
scalar,
u256 - field,
u256 - scalar,
]

for (let i = 0; i < 512; i++) {
wasm.keccak_f1600(wasm.free_adr.value)
wasm.keccak_f1600(wasm.free_adr.value + 56)
u256s.push(readU256(wasm.free_adr.value))
}

const aAdr = wasm.free_adr.value
const bAdr = wasm.free_adr.value + 256
const oAdr = wasm.free_adr.value + 512

Deno.test("u256 add / sub", () => {
for (const aU256 of u256s) {
for (const bU256 of u256s) {
writeU256(aAdr, aU256)
writeU256(bAdr, bU256)
wasm._u256_add(aAdr, 1n, bAdr, 0n)
assertU256Equals(readU256(aAdr), (aU256 + bU256) % u256)

writeU256(aAdr, aU256)
writeU256(bAdr, bU256)
wasm.u256_sub(oAdr, aAdr, bAdr)
assertU256Equals(readU256(oAdr), (u256 + aU256 - bU256) % u256)
}
}
})

Deno.test("mod field / mod scalar", () => {
for (const aU256 of u256s) {
writeU256(aAdr, aU256)
wasm.u256_mod_neg(aAdr, wasm.neg_field.value)
assertU256Equals(readU256(aAdr), aU256 % field)
writeU256(aAdr, aU256)
wasm.u256_mod_neg(aAdr, wasm.neg_scalar.value)
assertU256Equals(readU256(aAdr), aU256 % scalar)
}
})

Deno.test("field add", () => {
for (const aU256 of u256s) {
for (const bU256 of u256s) {
writeU256(aAdr, aU256 % field)
writeU256(bAdr, bU256 % field)
wasm.field_add(aAdr, bAdr)
assertU256Equals(readU256(aAdr), (aU256 + bU256) % field)
}
}
})

Deno.test("scalar add", () => {
for (const aU256 of u256s) {
for (const bU256 of u256s) {
writeU256(aAdr, aU256 % scalar)
writeU256(bAdr, bU256 % scalar)
wasm.scalar_add(aAdr, bAdr)
assertU256Equals(readU256(aAdr), (aU256 + bU256) % scalar)
}
}
})

Deno.test("u256 mul u512", () => {
for (const aU256 of u256s) {
for (const bU256 of u256s) {
writeU256(aAdr, aU256)
writeU256(bAdr, bU256)
mem.fill(0, oAdr, oAdr + 64)
wasm._u256_mul_u512(oAdr, aAdr, bAdr)
assertU512Equals(readU512(oAdr), (aU256 * bU256) % u512)
}
}
})

Deno.test("field mul", () => {
for (const aU256 of u256s) {
for (const bU256 of u256s) {
writeU256(aAdr, aU256)
writeU256(bAdr, bU256)
wasm.field_mul(aAdr, bAdr)
assertU256Equals(readU256(aAdr), (aU256 * bU256) % field)
}
}
})

Deno.test("scalar mul", () => {
for (const aU256 of u256s) {
for (const bU256 of u256s) {
writeU256(aAdr, aU256)
writeU256(bAdr, bU256)
wasm.scalar_mul(aAdr, bAdr)
assertU256Equals(readU256(aAdr), (aU256 * bU256) % scalar)
}
}
})

Deno.test("field invsqrt", () => {
for (const aU256 of u256s) {
if ((aU256 % field) === 0n) continue
writeU256(aAdr, aU256 % field)
if (wasm.field_invsqrt(aAdr)) {
assertU256Equals(readU256(aAdr) ** 2n * aU256 % field, 1n)
} else {
assertU256Equals(readU256(aAdr) ** 2n * aU256 % field, fieldI)
}
}
})

function readU512(adr: number) {
return readU256(adr) | (readU256(adr + 32) << 256n)
}

function assertU256Equals(a: bigint, b: bigint) {
if (a !== b) {
assertEquals(fmtLongInt(a, 256), fmtLongInt(b, 256))
}
}

function assertU512Equals(a: bigint, b: bigint) {
if (a !== b) {
assertEquals(fmtLongInt(a, 512), fmtLongInt(b, 512))
}
}

function fmtLongInt(x: bigint, bits: number) {
return fmtInt(x, bits).split(/(?=(?:.{8})+$)/).join("_")
}

function fmtInt(x: number | bigint, bits: number) {
return x
.toString(16)
.padStart(bits / 4, "0")
.split(/(?=(?:..)+$)/)
.reverse()
.join("")
}
76 changes: 76 additions & 0 deletions sr25519/keccak.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { assertEquals } from "https://deno.land/[email protected]/testing/asserts.ts"
import { instantiate } from "./sr25519.ts"

const { mem, wasm } = instantiate()

const state = new BigUint64Array(mem.buffer, wasm.free_adr.value, 25)

Deno.test("keccak", () => {
state.fill(0n)

wasm.keccak_f1600(state.byteOffset)

assertEquals(
state,
new BigUint64Array([
0xf1258f7940e1dde7n,
0x84d5ccf933c0478an,
0xd598261ea65aa9een,
0xbd1547306f80494dn,
0x8b284e056253d057n,
0xff97a42d7f8e6fd4n,
0x90fee5a0a44647c4n,
0x8c5bda0cd6192e76n,
0xad30a6f71b19059cn,
0x30935ab7d08ffc64n,
0xeb5aa93f2317d635n,
0xa9a6e6260d712103n,
0x81a57c16dbcf555fn,
0x43b831cd0347c826n,
0x01f22f1a11a5569fn,
0x05e5635a21d9ae61n,
0x64befef28cc970f2n,
0x613670957bc46611n,
0xb87c5a554fd00ecbn,
0x8c3ee88a1ccf32c8n,
0x940c7922ae3a2614n,
0x1841f924a2c509e4n,
0x16f53526e70465c2n,
0x75f644e97f30a13bn,
0xeaf1ff7b5ceca249n,
]),
)

wasm.keccak_f1600(state.byteOffset)

assertEquals(
state,
new BigUint64Array([
0x2d5c954df96ecb3cn,
0x6a332cd07057b56dn,
0x093d8d1270d76b6cn,
0x8a20d9b25569d094n,
0x4f9c4f99e5e7f156n,
0xf957b9a2da65fb38n,
0x85773dae1275af0dn,
0xfaf4f247c3d810f7n,
0x1f1b9ee6f79a8759n,
0xe4fecc0fee98b425n,
0x68ce61b6b9ce68a1n,
0xdeea66c4ba8f974fn,
0x33c43d836eafb1f5n,
0xe00654042719dbd9n,
0x7cf8a9f009831265n,
0xfd5449a6bf174743n,
0x97ddad33d8994b40n,
0x48ead5fc5d0be774n,
0xe3b8c8ee55b7b03cn,
0x91a0226e649e42e9n,
0x900e3129e7badd7bn,
0x202a9ec5faa3cce8n,
0x5b3402464e1c3db6n,
0x609f4e62a44c1059n,
0x20d06cd26a8fbf5cn,
]),
)
})
30 changes: 30 additions & 0 deletions sr25519/keccak.wasm.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// @generated

import { decodeHex } from "../common/hex.ts"

export default decodeHex(
"\
0061736d01000000011f0560017f027f7e60027f7e017f60047f7e7f7e027f7e\
60017f017f60017f0002100104686f7374066d656d6f72790200010306050001\
020304060c027f0041000b7f0041c0010b0720020d6b656363616b5f72635f61\
647203000c6b656363616b5f663136303000040ab604052500200041086a2000\
29030020002903288520002903508520002903788520002903a001850b4a0020\
0041086a20002000290300200185370300200020002903282001853703282000\
200029035020018537035020002000290378200185370378200020002903a001\
2001853703a0010b18002000200020026a220029030020002001200389370300\
0b7c01057e200041286a20002903002101200029030821022000290310210320\
002903182104200029032021052000200120032002427f858385370300200020\
0220042003427f8583853703082000200320052004427f858385370310200020\
0420012005427f8583853703182000200520022001427f8583853703200bac02\
02017f067e230021010340200010002102100021031000210410002105100021\
061a200020062003420189851001200220044201898510012003200542018985\
100120042006420189851001200520024201898510011a2000200029030841d0\
004201100241384203100241d80042061002418801420a1002419001420f1002\
4118421510024128421c10024180014224100241c000422d100241a801423710\
0241c001420210024120420e100241f800421b100241b8014229100241980142\
38100241e8004208100241e000421910024110422b100241a001423e100241f0\
004212100241b0014227100241c800423d10024130421410024108422c10021a\
1a2000100310031003100310031a200020002903002001290300853703002001\
41086a22012301490d000b0b\
",
)
Loading

0 comments on commit a96745c

Please sign in to comment.