split crypto from std once again

This commit is contained in:
2026-01-04 10:25:54 +01:00
parent c603d10012
commit 420f296ca5
3 changed files with 295 additions and 291 deletions

View File

@@ -64,7 +64,12 @@ fn compile_file(args: Args) -> Result<(), ZernError> {
let mut analyzer = analyzer::Analyzer::new();
let mut codegen = codegen_x86_64::CodegenX86_64::new(&mut analyzer);
codegen.emit_prologue()?;
compile_file_to(&mut codegen, "std.zr", include_str!("std.zr").into())?;
compile_file_to(&mut codegen, "std.zr", include_str!("std/std.zr").into())?;
compile_file_to(
&mut codegen,
"crypto.zr",
include_str!("std/crypto.zr").into(),
)?;
compile_file_to(&mut codegen, filename, source)?;
if !args.output_asm {

288
src/std/crypto.zr Normal file
View File

@@ -0,0 +1,288 @@
func crypto.rotl32[x: i64, r: i64] : i64
return ((x << r) | (x >> (32 - r))) & 0xffffffff
func crypto.chacha20._quarter_round[state: ptr, a: i64, b: i64, c: i64, d: i64] : void
let va: i64 = mem.read32(state + a * 4)
let vb: i64 = mem.read32(state + b * 4)
let vc: i64 = mem.read32(state + c * 4)
let vd: i64 = mem.read32(state + d * 4)
va = (va + vb) & 0xffffffff
vd = vd ^ va
vd = crypto.rotl32(vd, 16)
vc = (vc + vd) & 0xffffffff
vb = vb ^ vc
vb = crypto.rotl32(vb, 12)
va = (va + vb) & 0xffffffff
vd = vd ^ va
vd = crypto.rotl32(vd, 8)
vc = (vc + vd) & 0xffffffff
vb = vb ^ vc
vb = crypto.rotl32(vb, 7)
mem.write32(state + a * 4, va)
mem.write32(state + b * 4, vb)
mem.write32(state + c * 4, vc)
mem.write32(state + d * 4, vd)
func crypto.xchacha20._permute[state: ptr] : void
for i in 0..10
crypto.chacha20._quarter_round(state, 0, 4, 8, 12)
crypto.chacha20._quarter_round(state, 1, 5, 9, 13)
crypto.chacha20._quarter_round(state, 2, 6, 10, 14)
crypto.chacha20._quarter_round(state, 3, 7, 11, 15)
crypto.chacha20._quarter_round(state, 0, 5, 10, 15)
crypto.chacha20._quarter_round(state, 1, 6, 11, 12)
crypto.chacha20._quarter_round(state, 2, 7, 8, 13)
crypto.chacha20._quarter_round(state, 3, 4, 9, 14)
func crypto.xchacha20._block[key: ptr, nonce: ptr, blocknum: i64, out: ptr] : void
let sigma: str = "expand 32-byte k"
let state: ptr = mem.alloc(16 * 4)
mem.write32(state + 0, mem.read32(sigma + 0))
mem.write32(state + 4, mem.read32(sigma + 4))
mem.write32(state + 8, mem.read32(sigma + 8))
mem.write32(state + 12, mem.read32(sigma + 12))
for i in 0..8
mem.write32(state + (4 + i) * 4, mem.read32(key + i * 4))
mem.write32(state + 12 * 4, blocknum)
mem.write32(state + 13 * 4, mem.read32(nonce + 0))
mem.write32(state + 14 * 4, mem.read32(nonce + 4))
mem.write32(state + 15 * 4, mem.read32(nonce + 8))
let working: ptr = mem.alloc(16 * 4)
for i in 0..16
mem.write32(working + i * 4, mem.read32(state + i * 4))
crypto.xchacha20._permute(working)
for i in 0..16
let v: i64 = (mem.read32(working + i * 4) + mem.read32(state + i * 4)) & 0xffffffff
mem.write32(out + i * 4, v)
mem.free(working)
mem.free(state)
func crypto.xchacha20._hchacha20[key: ptr, input: ptr, out32: ptr] : void
let sigma: str = "expand 32-byte k"
let state: ptr = mem.alloc(16 * 4)
mem.write32(state + 0, mem.read32(sigma + 0))
mem.write32(state + 4, mem.read32(sigma + 4))
mem.write32(state + 8, mem.read32(sigma + 8))
mem.write32(state + 12, mem.read32(sigma + 12))
for i in 0..8
mem.write32(state + (4 + i) * 4, mem.read32(key + i * 4))
for i in 0..4
mem.write32(state + (12 + i) * 4, mem.read32(input + i * 4))
crypto.xchacha20._permute(state)
for i in 0..4
mem.write32(out32 + i * 4, mem.read32(state + i * 4))
for i in 0..4
mem.write32(out32 + 16 + i * 4, mem.read32(state + (12 + i) * 4))
mem.free(state)
func crypto.xchacha20._stream[key: ptr, nonce: ptr, out: ptr, len: i64] : void
let subkey: ptr = mem.alloc(32)
crypto.xchacha20._hchacha20(key, nonce, subkey)
let nonce12: ptr = mem.alloc(12)
for i in 0..12
mem.write8(nonce12 + i, 0)
for i in 0..8
mem.write8(nonce12 + 4 + i, nonce[16 + i])
let blocknum: i64 = 0
let remaining: i64 = len
let block: ptr = mem.alloc(64)
while remaining > 0
crypto.xchacha20._block(subkey, nonce12, blocknum, block)
let take: i64 = 64
if remaining < 64
take = remaining
for i in 0..take
mem.write8(out + (len - remaining) + i, block[i])
remaining = remaining - take
blocknum = blocknum + 1
mem.free(block)
mem.free(nonce12)
mem.free(subkey)
func crypto.xchacha20.xor[key: ptr, nonce: ptr, input: ptr, len: i64] : ptr
if len <= 0
return dbg.panic("empty buffer passed to crypto.xchacha20.xor")
let out: ptr = mem.alloc(len)
let ks: ptr = mem.alloc(len)
crypto.xchacha20._stream(key, nonce, ks, len)
for i in 0..len
mem.write8(out + i, input[i] ^ ks[i])
mem.free(ks)
return out
func crypto.x25519.carry[elem: ptr] : void
for i in 0..16
let carry: i64 = mem.read64(elem + i * 8) >> 16
mem.write64(elem + i * 8, mem.read64(elem + i * 8) - (carry << 16))
if i < 15
mem.write64(elem + (i + 1) * 8, mem.read64(elem + (i + 1) * 8) + carry)
else
mem.write64(elem, mem.read64(elem) + 38 * carry)
func crypto.x25519.fadd[out: ptr, a: ptr, b: ptr] : void
for i in 0..16
mem.write64(out + i * 8, mem.read64(a + i * 8) + mem.read64(b + i * 8))
func crypto.x25519.fsub[out: ptr, a: ptr, b: ptr] : void
for i in 0..16
mem.write64(out + i * 8, mem.read64(a + i * 8) - mem.read64(b + i * 8))
func crypto.x25519.fmul[out: ptr, a: ptr, b: ptr] : void
let product: ptr = mem.alloc(31 * 8)
for i in 0..31
mem.write64(product + i * 8, 0)
for i in 0..16
for j in 0..16
mem.write64(product + (i + j) * 8, mem.read64(product + (i + j) * 8) + (mem.read64(a + i * 8) * mem.read64(b + j * 8)))
for i in 0..15
mem.write64(product + i * 8, mem.read64(product + i * 8) + 38 * mem.read64(product + (i + 16) * 8))
for i in 0..16
mem.write64(out + i * 8, mem.read64(product + i * 8))
crypto.x25519.carry(out)
crypto.x25519.carry(out)
mem.free(product)
func crypto.x25519.finverse[out: ptr, input: ptr] : void
let c: ptr = mem.alloc(16 * 8)
for i in 0..16
mem.write64(c + i * 8, mem.read64(input + i * 8))
let i = 253
while i >= 0
crypto.x25519.fmul(c, c, c)
if i != 2 && i != 4
crypto.x25519.fmul(c, c, input)
i = i - 1
for i in 0..16
mem.write64(out + i * 8, mem.read64(c + i * 8))
mem.free(c)
func crypto.x25519.swap[p: ptr, q: ptr, bit: i64] : void
for i in 0..16
let t: i64 = (-bit) & (mem.read64(p + i * 8) ^ mem.read64(q + i * 8))
mem.write64(p + i * 8, mem.read64(p + i * 8) ^ t)
mem.write64(q + i * 8, mem.read64(q + i * 8) ^ t)
func crypto.x25519.unpack[out: ptr, input: ptr] : void
for i in 0..16
mem.write64(out + i * 8, input[i * 2] + (input[i * 2 + 1] << 8))
mem.write64(out + 8 * 15, mem.read64(out + 8 * 15) & 0x7fff)
func crypto.x25519.pack[out: ptr, input: ptr] : void
let t: ptr = mem.alloc(16 * 8)
for i in 0..16
mem.write64(t + i * 8, mem.read64(input + i * 8))
let m: ptr = mem.alloc(16 * 8)
crypto.x25519.carry(t)
crypto.x25519.carry(t)
crypto.x25519.carry(t)
for j in 0..2
mem.write64(m, mem.read64(t) - 0xffed)
for i in 1..15
mem.write64(m + i * 8, mem.read64(t + i * 8) - 0xffff - ((mem.read64(m + (i - 1) * 8) >> 16) & 1))
mem.write64(m + (i - 1) * 8, mem.read64(m + (i - 1) * 8) & 0xffff)
mem.write64(m + 15 * 8, mem.read64(t + 15 * 8) - 0x7fff - ((mem.read64(m + 14 * 8) >> 16) & 1))
let carry: i64 = (mem.read64(m + 15 * 8) >> 16) & 1
mem.write64(m + 14 * 8, mem.read64(m + 14 * 8) & 0xffff)
crypto.x25519.swap(t, m, 1 - carry)
for i in 0..16
let v: i64 = mem.read64(t + i * 8)
mem.write8(out + i * 2, v & 0xff)
mem.write8(out + i * 2 + 1, (v >> 8) & 0xff)
mem.free(t)
mem.free(m)
func crypto.x25519.scalarmult[scalar: ptr, point: ptr] : ptr
let clamped: ptr = mem.alloc(32)
let a: ptr = mem.alloc(16 * 8)
let b: ptr = mem.alloc(16 * 8)
let c: ptr = mem.alloc(16 * 8)
let d: ptr = mem.alloc(16 * 8)
let e: ptr = mem.alloc(16 * 8)
let f: ptr = mem.alloc(16 * 8)
let x: ptr = mem.alloc(16 * 8)
let magic: ptr = mem.alloc(16 * 8)
mem.zero(magic, 16 * 8)
mem.write64(magic, 0xdb41) // 121665
mem.write64(magic + 8, 1)
// copy and clamp scalar
for i in 0..32
mem.write8(clamped + i, scalar[i])
mem.write8(clamped, clamped[0] & 0xf8)
mem.write8(clamped + 31, (clamped[31] & 0x7f) | 0x40)
// load point
crypto.x25519.unpack(x, point)
// initialize ladder state
for i in 0..16
mem.write64(a + i * 8, 0)
mem.write64(b + i * 8, mem.read64(x + i * 8))
mem.write64(c + i * 8, 0)
mem.write64(d + i * 8, 0)
mem.write64(a, 1)
mem.write64(d, 1)
let i = 254
while i >= 0
let bit: i64 = (clamped[i >> 3] >> (i & 7)) & 1
crypto.x25519.swap(a, b, bit)
crypto.x25519.swap(c, d, bit)
crypto.x25519.fadd(e, a, c)
crypto.x25519.fsub(a, a, c)
crypto.x25519.fadd(c, b, d)
crypto.x25519.fsub(b, b, d)
crypto.x25519.fmul(d, e, e)
crypto.x25519.fmul(f, a, a)
crypto.x25519.fmul(a, c, a)
crypto.x25519.fmul(c, b, e)
crypto.x25519.fadd(e, a, c)
crypto.x25519.fsub(a, a, c)
crypto.x25519.fmul(b, a, a)
crypto.x25519.fsub(c, d, f)
crypto.x25519.fmul(a, c, magic)
crypto.x25519.fadd(a, a, d)
crypto.x25519.fmul(c, c, a)
crypto.x25519.fmul(a, d, f)
crypto.x25519.fmul(d, b, x)
crypto.x25519.fmul(b, e, e)
crypto.x25519.swap(a, b, bit)
crypto.x25519.swap(c, d, bit)
i = i - 1
crypto.x25519.finverse(c, c)
crypto.x25519.fmul(a, a, c)
let out: ptr = mem.alloc(32)
crypto.x25519.pack(out, a)
mem.free(clamped)
mem.free(a)
mem.free(b)
mem.free(c)
mem.free(d)
mem.free(e)
mem.free(f)
mem.free(x)
mem.free(magic)
return out

View File

@@ -664,293 +664,4 @@ func net.close[s: i64] : void
_builtin_syscall(3, s)
func net.pack_addr[a: i64, b: i64, c: i64, d: i64] : i64
return (a << 24) | (b << 16) | (c << 8) | d
func crypto.rotl32[x: i64, r: i64] : i64
return ((x << r) | (x >> (32 - r))) & 0xffffffff
func crypto.chacha20._quarter_round[state: ptr, a: i64, b: i64, c: i64, d: i64] : void
let va: i64 = mem.read32(state + a * 4)
let vb: i64 = mem.read32(state + b * 4)
let vc: i64 = mem.read32(state + c * 4)
let vd: i64 = mem.read32(state + d * 4)
va = (va + vb) & 0xffffffff
vd = vd ^ va
vd = crypto.rotl32(vd, 16)
vc = (vc + vd) & 0xffffffff
vb = vb ^ vc
vb = crypto.rotl32(vb, 12)
va = (va + vb) & 0xffffffff
vd = vd ^ va
vd = crypto.rotl32(vd, 8)
vc = (vc + vd) & 0xffffffff
vb = vb ^ vc
vb = crypto.rotl32(vb, 7)
mem.write32(state + a * 4, va)
mem.write32(state + b * 4, vb)
mem.write32(state + c * 4, vc)
mem.write32(state + d * 4, vd)
func crypto.xchacha20._permute[state: ptr] : void
for i in 0..10
crypto.chacha20._quarter_round(state, 0, 4, 8, 12)
crypto.chacha20._quarter_round(state, 1, 5, 9, 13)
crypto.chacha20._quarter_round(state, 2, 6, 10, 14)
crypto.chacha20._quarter_round(state, 3, 7, 11, 15)
crypto.chacha20._quarter_round(state, 0, 5, 10, 15)
crypto.chacha20._quarter_round(state, 1, 6, 11, 12)
crypto.chacha20._quarter_round(state, 2, 7, 8, 13)
crypto.chacha20._quarter_round(state, 3, 4, 9, 14)
func crypto.xchacha20._block[key: ptr, nonce: ptr, blocknum: i64, out: ptr] : void
let sigma: str = "expand 32-byte k"
let state: ptr = mem.alloc(16 * 4)
mem.write32(state + 0, mem.read32(sigma + 0))
mem.write32(state + 4, mem.read32(sigma + 4))
mem.write32(state + 8, mem.read32(sigma + 8))
mem.write32(state + 12, mem.read32(sigma + 12))
for i in 0..8
mem.write32(state + (4 + i) * 4, mem.read32(key + i * 4))
mem.write32(state + 12 * 4, blocknum)
mem.write32(state + 13 * 4, mem.read32(nonce + 0))
mem.write32(state + 14 * 4, mem.read32(nonce + 4))
mem.write32(state + 15 * 4, mem.read32(nonce + 8))
let working: ptr = mem.alloc(16 * 4)
for i in 0..16
mem.write32(working + i * 4, mem.read32(state + i * 4))
crypto.xchacha20._permute(working)
for i in 0..16
let v: i64 = (mem.read32(working + i * 4) + mem.read32(state + i * 4)) & 0xffffffff
mem.write32(out + i * 4, v)
mem.free(working)
mem.free(state)
func crypto.xchacha20._hchacha20[key: ptr, input: ptr, out32: ptr] : void
let sigma: str = "expand 32-byte k"
let state: ptr = mem.alloc(16 * 4)
mem.write32(state + 0, mem.read32(sigma + 0))
mem.write32(state + 4, mem.read32(sigma + 4))
mem.write32(state + 8, mem.read32(sigma + 8))
mem.write32(state + 12, mem.read32(sigma + 12))
for i in 0..8
mem.write32(state + (4 + i) * 4, mem.read32(key + i * 4))
for i in 0..4
mem.write32(state + (12 + i) * 4, mem.read32(input + i * 4))
crypto.xchacha20._permute(state)
for i in 0..4
mem.write32(out32 + i * 4, mem.read32(state + i * 4))
for i in 0..4
mem.write32(out32 + 16 + i * 4, mem.read32(state + (12 + i) * 4))
mem.free(state)
func crypto.xchacha20._stream[key: ptr, nonce: ptr, out: ptr, len: i64] : void
let subkey: ptr = mem.alloc(32)
crypto.xchacha20._hchacha20(key, nonce, subkey)
let nonce12: ptr = mem.alloc(12)
for i in 0..12
mem.write8(nonce12 + i, 0)
for i in 0..8
mem.write8(nonce12 + 4 + i, nonce[16 + i])
let blocknum: i64 = 0
let remaining: i64 = len
let block: ptr = mem.alloc(64)
while remaining > 0
crypto.xchacha20._block(subkey, nonce12, blocknum, block)
let take: i64 = 64
if remaining < 64
take = remaining
for i in 0..take
mem.write8(out + (len - remaining) + i, block[i])
remaining = remaining - take
blocknum = blocknum + 1
mem.free(block)
mem.free(nonce12)
mem.free(subkey)
func crypto.xchacha20.xor[key: ptr, nonce: ptr, input: ptr, len: i64] : ptr
if len <= 0
return dbg.panic("empty buffer passed to crypto.xchacha20.xor")
let out: ptr = mem.alloc(len)
let ks: ptr = mem.alloc(len)
crypto.xchacha20._stream(key, nonce, ks, len)
for i in 0..len
mem.write8(out + i, input[i] ^ ks[i])
mem.free(ks)
return out
func crypto.x25519.carry[elem: ptr] : void
for i in 0..16
let carry: i64 = mem.read64(elem + i * 8) >> 16
mem.write64(elem + i * 8, mem.read64(elem + i * 8) - (carry << 16))
if i < 15
mem.write64(elem + (i + 1) * 8, mem.read64(elem + (i + 1) * 8) + carry)
else
mem.write64(elem, mem.read64(elem) + 38 * carry)
func crypto.x25519.fadd[out: ptr, a: ptr, b: ptr] : void
for i in 0..16
mem.write64(out + i * 8, mem.read64(a + i * 8) + mem.read64(b + i * 8))
func crypto.x25519.fsub[out: ptr, a: ptr, b: ptr] : void
for i in 0..16
mem.write64(out + i * 8, mem.read64(a + i * 8) - mem.read64(b + i * 8))
func crypto.x25519.fmul[out: ptr, a: ptr, b: ptr] : void
let product: ptr = mem.alloc(31 * 8)
for i in 0..31
mem.write64(product + i * 8, 0)
for i in 0..16
for j in 0..16
mem.write64(product + (i + j) * 8, mem.read64(product + (i + j) * 8) + (mem.read64(a + i * 8) * mem.read64(b + j * 8)))
for i in 0..15
mem.write64(product + i * 8, mem.read64(product + i * 8) + 38 * mem.read64(product + (i + 16) * 8))
for i in 0..16
mem.write64(out + i * 8, mem.read64(product + i * 8))
crypto.x25519.carry(out)
crypto.x25519.carry(out)
mem.free(product)
func crypto.x25519.finverse[out: ptr, input: ptr] : void
let c: ptr = mem.alloc(16 * 8)
for i in 0..16
mem.write64(c + i * 8, mem.read64(input + i * 8))
let i = 253
while i >= 0
crypto.x25519.fmul(c, c, c)
if i != 2 && i != 4
crypto.x25519.fmul(c, c, input)
i = i - 1
for i in 0..16
mem.write64(out + i * 8, mem.read64(c + i * 8))
mem.free(c)
func crypto.x25519.swap[p: ptr, q: ptr, bit: i64] : void
for i in 0..16
let t: i64 = (-bit) & (mem.read64(p + i * 8) ^ mem.read64(q + i * 8))
mem.write64(p + i * 8, mem.read64(p + i * 8) ^ t)
mem.write64(q + i * 8, mem.read64(q + i * 8) ^ t)
func crypto.x25519.unpack[out: ptr, input: ptr] : void
for i in 0..16
mem.write64(out + i * 8, input[i * 2] + (input[i * 2 + 1] << 8))
mem.write64(out + 8 * 15, mem.read64(out + 8 * 15) & 0x7fff)
func crypto.x25519.pack[out: ptr, input: ptr] : void
let t: ptr = mem.alloc(16 * 8)
for i in 0..16
mem.write64(t + i * 8, mem.read64(input + i * 8))
let m: ptr = mem.alloc(16 * 8)
crypto.x25519.carry(t)
crypto.x25519.carry(t)
crypto.x25519.carry(t)
for j in 0..2
mem.write64(m, mem.read64(t) - 0xffed)
for i in 1..15
mem.write64(m + i * 8, mem.read64(t + i * 8) - 0xffff - ((mem.read64(m + (i - 1) * 8) >> 16) & 1))
mem.write64(m + (i - 1) * 8, mem.read64(m + (i - 1) * 8) & 0xffff)
mem.write64(m + 15 * 8, mem.read64(t + 15 * 8) - 0x7fff - ((mem.read64(m + 14 * 8) >> 16) & 1))
let carry: i64 = (mem.read64(m + 15 * 8) >> 16) & 1
mem.write64(m + 14 * 8, mem.read64(m + 14 * 8) & 0xffff)
crypto.x25519.swap(t, m, 1 - carry)
for i in 0..16
let v: i64 = mem.read64(t + i * 8)
mem.write8(out + i * 2, v & 0xff)
mem.write8(out + i * 2 + 1, (v >> 8) & 0xff)
mem.free(t)
mem.free(m)
func crypto.x25519.scalarmult[scalar: ptr, point: ptr] : ptr
let clamped: ptr = mem.alloc(32)
let a: ptr = mem.alloc(16 * 8)
let b: ptr = mem.alloc(16 * 8)
let c: ptr = mem.alloc(16 * 8)
let d: ptr = mem.alloc(16 * 8)
let e: ptr = mem.alloc(16 * 8)
let f: ptr = mem.alloc(16 * 8)
let x: ptr = mem.alloc(16 * 8)
let magic: ptr = mem.alloc(16 * 8)
mem.zero(magic, 16 * 8)
mem.write64(magic, 0xdb41) // 121665
mem.write64(magic + 8, 1)
// copy and clamp scalar
for i in 0..32
mem.write8(clamped + i, scalar[i])
mem.write8(clamped, clamped[0] & 0xf8)
mem.write8(clamped + 31, (clamped[31] & 0x7f) | 0x40)
// load point
crypto.x25519.unpack(x, point)
// initialize ladder state
for i in 0..16
mem.write64(a + i * 8, 0)
mem.write64(b + i * 8, mem.read64(x + i * 8))
mem.write64(c + i * 8, 0)
mem.write64(d + i * 8, 0)
mem.write64(a, 1)
mem.write64(d, 1)
let i = 254
while i >= 0
let bit: i64 = (clamped[i >> 3] >> (i & 7)) & 1
crypto.x25519.swap(a, b, bit)
crypto.x25519.swap(c, d, bit)
crypto.x25519.fadd(e, a, c)
crypto.x25519.fsub(a, a, c)
crypto.x25519.fadd(c, b, d)
crypto.x25519.fsub(b, b, d)
crypto.x25519.fmul(d, e, e)
crypto.x25519.fmul(f, a, a)
crypto.x25519.fmul(a, c, a)
crypto.x25519.fmul(c, b, e)
crypto.x25519.fadd(e, a, c)
crypto.x25519.fsub(a, a, c)
crypto.x25519.fmul(b, a, a)
crypto.x25519.fsub(c, d, f)
crypto.x25519.fmul(a, c, magic)
crypto.x25519.fadd(a, a, d)
crypto.x25519.fmul(c, c, a)
crypto.x25519.fmul(a, d, f)
crypto.x25519.fmul(d, b, x)
crypto.x25519.fmul(b, e, e)
crypto.x25519.swap(a, b, bit)
crypto.x25519.swap(c, d, bit)
i = i - 1
crypto.x25519.finverse(c, c)
crypto.x25519.fmul(a, a, c)
let out: ptr = mem.alloc(32)
crypto.x25519.pack(out, a)
mem.free(clamped)
mem.free(a)
mem.free(b)
mem.free(c)
mem.free(d)
mem.free(e)
mem.free(f)
mem.free(x)
mem.free(magic)
return out
return (a << 24) | (b << 16) | (c << 8) | d