urbit-ob

JavaScript utilities for phonemic base wrangling.
Log | Files | Refs | README

commit ea5fa025785ad00e46c514733ccc52b87f9a8ea7
parent f808c8884968b4cb30119f59f066e5c93cc0d490
Author: Jared Tobin <jared@jtobin.io>
Date:   Tue, 12 Mar 2019 18:43:39 +1300

Generalise 'Fe' to support other PRFs.

Passing 'Fe' an explicit pseudorandom function allows us to easily test
it on other (i.e. smaller) input spaces.

Diffstat:
Msrc/internal/ob.js | 153++++++++++++++++++++++++++++++++++++++++++-------------------------------------
1 file changed, 81 insertions(+), 72 deletions(-)

diff --git a/src/internal/ob.js b/src/internal/ob.js @@ -14,6 +14,39 @@ const ux_ffff_ffff_0000_0000 = new BN('ffffffff00000000', 'hex') const u_65535 = new BN('65535') const u_65536 = new BN('65536') +// PRF seeds +const raku = [ + 0xb76d5eed, + 0xee281300, + 0x85bcae01, + 0x4b387af7, +] + +// a PRF for j in { 0, .., 3 } +const F = (j, arg) => + muk(raku[j], 2, arg) + +/** + * Conceal structure v3. + * + * @param {String, Number, BN} pyn + * @return {BN} + */ +const fein = (arg) => { + const loop = (pyn) => { + const lo = pyn.and(ux_ffff_ffff) + const hi = pyn.and(ux_ffff_ffff_0000_0000) + + return pyn.gte(ux_1_0000) && pyn.lte(ux_ffff_ffff) + ? ux_1_0000.add(feis(pyn.sub(ux_1_0000))) + : pyn.gte(ux_1_0000_0000) && pyn.lte(ux_ffff_ffff_ffff_ffff) + ? hi.or(loop(lo)) + : pyn + } + + return loop(new BN(arg)) +} + /** * Conceal structure v2. * @@ -57,6 +90,52 @@ const fend = (arg) => { } /** + * Generalised Feistel cipher. + * + * See: Black and Rogaway (2002), "Ciphers with arbitrary finite domains." + * + * @param {String, Number, BN} + * @return {BN} + */ +const feis = arg => + Fe(4, u_65535, u_65536, ux_ffff_ffff, F, new BN(arg)) + +const Fe = (r, a, b, k, f, m) => { + const c = fe(r, a, b, f, m) + return ( + c.lt(k) + ? c + : fe(r, a, b, f, c) + ) +} + +const fe = (r, a, b, f, m) => { + const loop = (j, ell, arr) => { + if (j > r) { + return ( + r % 2 !== 0 + ? a.mul(ell).add(arr) + : a.mul(arr).add(ell) + ) + } else { + const eff = f(j - 1, arr) + + const tmp = + j % 2 !== 0 + ? ell.add(eff).mod(a) + : ell.add(eff).mod(b) + + return loop(j + 1, arr, tmp) + } + } + + const L = m.mod(a) + const R = m.div(a) + + return loop(1, L, R) +} + +/** * Adapted from Black and Rogaway "Ciphers with arbitrary finite domains", * 2002. * @@ -107,13 +186,6 @@ const rynd = (n, arr) => { return [ r, l.add(muk(raku[n], 2, r)).mod(p) ] } -const raku = [ - 0xb76d5eed, - 0xee281300, - 0x85bcae01, - 0x4b387af7, -] - /** * Reverse round. * @@ -128,71 +200,6 @@ const rund = (n, arr) => { return [ r, l.add(p).sub(muk(raku[n], 2, r).mod(p)).mod(p) ] } - -const Fe = (r, a, b, k, f, m) => { - const c = fe(r, a, b, f, m) - return ( - c.lt(k) - ? c - : fe(r, a, b, f, c) - ) -} - -const fe = (r, a, b, f, m) => { - const loop = (j, ell, arr) => { - if (j > r) { - return ( - r % 2 !== 0 - ? a.mul(ell).add(arr) - : a.mul(arr).add(ell) - ) - } else { - const eff = f(r - j, arr) - - const tmp = - j % 2 !== 0 - ? ell.add(eff).mod(a) - : ell.add(eff).mod(b) - - return loop(j + 1, arr, tmp) - } - } - - const L = m.mod(a) - const R = m.div(a) - - return loop(1, L, R) -} - -const F = (j, arr) => { - const raku = [ - 0xb76d5eed, - 0xee281300, - 0x85bcae01, - 0x4b387af7, - ] - - return muk(raku[j], 2, arr) -} - -const feis = arg => - Fe(4, u_65535, u_65536, ux_ffff_ffff, F, new BN(arg)) - -const fein = (arg) => { - const loop = (pyn) => { - const lo = pyn.and(ux_ffff_ffff) - const hi = pyn.and(ux_ffff_ffff_0000_0000) - - return pyn.gte(ux_1_0000) && pyn.lte(ux_ffff_ffff) - ? ux_1_0000.add(feis(pyn.sub(ux_1_0000))) - : pyn.gte(ux_1_0000_0000) && pyn.lte(ux_ffff_ffff_ffff_ffff) - ? hi.or(loop(lo)) - : pyn - } - - return loop(new BN(arg)) -} - module.exports = { feen, fend, @@ -200,6 +207,8 @@ module.exports = { teil, rynd, rund, + + F, raku, fe,