urbit-ob

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

commit 2c5c28e55c353c2008af80ab82e2f17afd3862ae
parent fb3353e1d5178c69f5c17b9ba472df4d84e726e9
Author: Jared Tobin <jared@jtobin.io>
Date:   Tue, 12 Mar 2019 15:25:51 +1300

Add @p tests.

Adds exhaustive tests for 'feis' over small and medium input spaces.

Diffstat:
Msrc/internal/ob.js | 95++++++++++++++++++++++---------------------------------------------------------
Mtest/med.js | 101+++++++++++++++++++++++++++++--------------------------------------------------
Mtest/small.js | 63++++++++++++++++++++-------------------------------------------
Dtest/tiny.js | 72------------------------------------------------------------------------
4 files changed, 83 insertions(+), 248 deletions(-)

diff --git a/src/internal/ob.js b/src/internal/ob.js @@ -107,6 +107,13 @@ const rynd = (n, arr) => { return [ r, l.add(muk(raku[n], 2, r)).mod(p) ] } +const raku = [ + 0xb76d5eed, + 0xee281300, + 0x85bcae01, + 0x4b387af7, +] + /** * Reverse round. * @@ -121,78 +128,17 @@ const rund = (n, arr) => { return [ r, l.add(p).sub(muk(raku[n], 2, r).mod(p)).mod(p) ] } -const raku = [ - 0xb76d5eed, - 0xee281300, - 0x85bcae01, - 0x4b387af7, -] -const Fe = (r, a, b, k, m) => { - const c = fe(r, a, b, m) +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, c) + : fe(r, a, b, f, c) ) } -// this is the "official" version that seems to correspond to the paper -// const fe = (r, a, b, m) => { -// const loop = (j, ell, arr) => { -// if (j === 0) { -// return ( -// r % 2 !== 0 -// ? a.mul(ell).add(arr) -// : a.mul(arr).add(ell) -// ) -// } else { -// const f = muk(raku[r - j], 2, arr) -// -// const tmp = -// j % 2 !== 0 -// ? ell.add(f).mod(a) -// : ell.add(f).mod(b) -// -// return loop(j - 1, arr, tmp) -// } -// } -// -// const L = m.mod(a) -// const R = m.div(a) -// -// return loop(r, L, R) -// } - -// const fe = (r, a, b, m) => { -// const loop = (j, ell, arr) => { -// console.log(`${ell.toString()} ${arr.toString()}`) -// if (j === 0) { -// return ( -// r % 2 !== 0 -// ? a.mul(ell).add(arr) -// : a.mul(arr).add(ell) -// ) -// } else { -// const f = muk(raku[r - j], 2, arr) -// -// const tmp = -// j % 2 !== 0 -// ? ell.add(f).mod(b) -// : ell.add(f).mod(a) -// -// return loop(j - 1, arr, tmp) -// } -// } -// -// const L = m.mod(a) -// const R = m.div(a) -// -// return loop(r, L, R) -// } - -// NB (jtobin): test me exhaustively -const fe = (r, a, b, m) => { +const fe = (r, a, b, f, m) => { const loop = (j, ell, arr) => { if (j > r) { return ( @@ -201,12 +147,12 @@ const fe = (r, a, b, m) => { : a.mul(arr).add(ell) ) } else { - const f = muk(raku[r - j], 2, arr) + const eff = f(r - j, arr) const tmp = j % 2 !== 0 - ? ell.add(f).mod(a) - : ell.add(f).mod(b) + ? ell.add(eff).mod(a) + : ell.add(eff).mod(b) return loop(j + 1, arr, tmp) } @@ -218,8 +164,19 @@ const fe = (r, a, b, m) => { 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, new BN(arg)) + Fe(4, u_65535, u_65536, ux_ffff_ffff, F, new BN(arg)) const fein = (arg) => { const loop = (pyn) => { diff --git a/test/med.js b/test/med.js @@ -1,8 +1,11 @@ const BN = require('bn.js') +const { expect } = require('chai') -const u_a = new BN(255) -const u_b = new BN(256) -const u_c = new BN(65280) +const { Fe } = require('../src/internal/ob') + +const u_a = new BN(Math.pow(2, 4) - 1) +const u_b = new BN(Math.pow(2, 4)) +const u_c = u_a.mul(u_b) const emm = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, @@ -19,76 +22,46 @@ const emm = [ 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, - 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, - 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 + 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239 ] - const v0 = [ - 71, 235, 196, 202, 11, 143, 250, 178, 182, 116, 94, 252, 253, 255, 179, 192, - 81, 44, 227, 152, 112, 90, 130, 43, 124, 103, 55, 75, 17, 147, 22, 224, - 27, 93, 51, 248, 218, 145, 146, 141, 48, 155, 54, 133, 41, 142, 207, 206, - 5, 236, 127, 110, 91, 176, 200, 216, 72, 23, 246, 251, 151, 122, 140, 219, - 14, 177, 135, 225, 201, 74, 36, 106, 0, 40, 247, 9, 203, 190, 53, 221, - 3, 121, 70, 132, 80, 46, 100, 181, 232, 197, 29, 62, 114, 213, 88, 153, - 243, 244, 86, 230, 69, 76, 123, 95, 96, 191, 150, 61, 210, 171, 20, 229, - 188, 159, 68, 19, 195, 125, 107, 59, 175, 49, 113, 242, 102, 128, 101, 105, - 237, 223, 118, 167, 240, 117, 4, 226, 144, 108, 208, 162, 129, 131, 99, 111, - 161, 77, 78, 185, 126, 205, 228, 233, 18, 194, 120, 249, 56, 85, 34, 154, - 98, 97, 241, 52, 7, 204, 16, 166, 58, 73, 234, 119, 50, 163, 12, 84, - 1, 214, 189, 238, 215, 82, 156, 66, 160, 33, 245, 115, 28, 24, 35, 57, - 173, 254, 172, 83, 168, 169, 64, 239, 165, 184, 139, 109, 148, 32, 26, 217, - 134, 39, 164, 174, 231, 222, 136, 47, 30, 199, 38, 211, 87, 25, 13, 138, - 193, 8, 170, 104, 212, 60, 89, 180, 10, 149, 45, 67, 15, 209, 186, 37, - 183, 65, 157, 158, 21, 92, 31, 198, 6, 42, 63, 2, 79, 137, 220, 187 - ].map(x => new BN(x)) - -const eff = m => v0[m] + 106, 54, 57, 110, 216, 157, 90, 138, 148, 205, 214, 229, 25, 104, 217, 70, 16, 91, + 180, 108, 189, 176, 67, 213, 154, 194, 122, 199, 136, 140, 36, 56, 87, 112, 8, 34, + 14, 171, 227, 160, 211, 228, 37, 121, 119, 65, 132, 45, 224, 61, 141, 59, 82, 77, + 74, 20, 130, 181, 123, 186, 166, 42, 81, 172, 105, 196, 44, 135, 156, 192, 116, 39, + 7, 40, 84, 169, 193, 131, 88, 142, 24, 128, 38, 222, 197, 218, 159, 30, 145, 58, + 53, 85, 62, 49, 158, 86, 72, 210, 225, 52, 73, 149, 143, 195, 124, 179, 219, 9, + 200, 64, 51, 48, 26, 234, 27, 232, 231, 153, 190, 133, 109, 126, 6, 178, 183, 151, + 117, 46, 161, 43, 185, 236, 127, 89, 223, 23, 69, 68, 209, 139, 19, 33, 79, 164, + 207, 50, 144, 31, 134, 170, 29, 107, 220, 184, 47, 103, 206, 201, 175, 125, 35, 114, + 146, 10, 55, 152, 98, 1, 168, 215, 28, 237, 101, 17, 155, 118, 83, 147, 115, 100, + 233, 4, 66, 0, 150, 203, 22, 5, 174, 11, 18, 177, 3, 165, 99, 167, 202, 212, + 163, 182, 80, 162, 71, 97, 12, 60, 113, 221, 204, 41, 226, 187, 63, 230, 2, 188, + 208, 76, 191, 235, 93, 13, 111, 238, 78, 198, 21, 92, 95, 94, 96, 102, 120, 239, + 32, 129, 15, 173, 137, 75 + ] -// NOTE this appears to be a correct implementation -const fe = (r, a, b, 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 f = eff(arr) +const eff = (_, m) => new BN(v0[m]) - const tmp = - j % 2 !== 0 - ? ell.add(f).mod(a) - : ell.add(f).mod(b) +const feis = arg => + Fe(4, u_a, u_b, u_c, eff, new BN(arg)) - return loop(j + 1, arr, tmp) - } - } +// test - const L = m.mod(a) - const R = m.div(a) +describe('feis -- medium input space', () => { - return loop(1, L, R) -} + const perm = emm.map(x => feis(x).toString()) + const distincts = perm.filter((x, i, a) => a.indexOf(x) === i) -const Fe = (r, a, b, k, m) => { - const c = fe(r, a, b, m) - return ( - c.lt(k) - ? c - : fe(r, a, b, c) - ) -} + it('produces distinct outputs', () => { + expect(distincts.length).to.equal(perm.length) + }) -const feis = arg => - Fe(4, u_a, u_b, u_c, new BN(arg)) + it('permutes the input space', () => { + expect(perm.reduce((acc, x) => emm.includes(parseInt(x)) && acc, true)) + .to.equal(true) + }) -module.exports = { - eff, - emm, - fe, - Fe, - feis -} +}) diff --git a/test/small.js b/test/small.js @@ -1,10 +1,11 @@ const BN = require('bn.js') +const { expect } = require('chai') -const u_a = new BN(3) -const u_b = new BN(4) -const u_c = new BN(12) +const { Fe } = require('../src/internal/ob') -const emm = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] +const u_a = new BN(Math.pow(2, 2) - 1) +const u_b = new BN(Math.pow(2, 2)) +const u_c = u_a.mul(u_b) const eff = (j, m) => { let v0 = [5, 9, 2, 6, 4, 0, 8, 7, 1, 10, 3, 11] @@ -23,49 +24,25 @@ const eff = (j, m) => { ) } -// NOTE this appears to be a correct implementation -const fe = (r, a, b, 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 f = eff(4 - j - 1, arr) +const feis = arg => + Fe(4, u_a, u_b, u_c, eff, new BN(arg)) - const tmp = - j % 2 !== 0 - ? ell.add(f).mod(a) - : ell.add(f).mod(b) +// test - return loop(j + 1, arr, tmp) - } - } +describe('feis -- small input space', () => { - const L = m.mod(a) - const R = m.div(a) + const emm = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] + const perm = emm.map(x => feis(x).toString()) + const distincts = perm.filter((x, i, a) => a.indexOf(x) === i) - return loop(1, L, R) -} + it('produces distinct outputs', () => { + expect(distincts.length).to.equal(perm.length) + }) -const Fe = (r, a, b, k, m) => { - const c = fe(r, a, b, m) - return ( - c.lt(k) - ? c - : fe(r, a, b, c) - ) -} + it('permutes the input space', () => { + expect(perm.reduce((acc, x) => emm.includes(parseInt(x)) && acc, true)) + .to.equal(true) + }) -const feis = arg => - Fe(4, u_a, u_b, u_c, new BN(arg)) +}) -module.exports = { - eff, - emm, - fe, - Fe, - feis -} diff --git a/test/tiny.js b/test/tiny.js @@ -1,72 +0,0 @@ -const BN = require('bn.js') - -const u_a = new BN(3) -const u_b = new BN(4) -const u_c = new BN(12) - -const emm = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] - -const eff = (j, m) => { - let v0 = [5, 9, 2, 6, 4, 0, 8, 7, 1, 10, 3, 11] - let v1 = [2, 1, 0, 3, 10, 4, 9, 5, 7, 11, 6, 8] - let v2 = [10, 6, 7, 1, 0, 11, 3, 9, 5, 2, 8, 4] - let v3 = [11, 0, 3, 5, 9, 8, 6, 10, 4, 1, 2, 7] - - return ( - j === 0 - ? new BN(v0[m]) - : j === 1 - ? new BN(v1[m]) - : j === 2 - ? new BN(v2[m]) - : new BN(v3[m]) - ) -} - -// NOTE this appears to be a correct implementation -const fe = (r, a, b, 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 f = eff(4 - j - 1, arr) - - const tmp = - j % 2 !== 0 - ? ell.add(f).mod(a) - : ell.add(f).mod(b) - - return loop(j + 1, arr, tmp) - } - } - - const L = m.mod(a) - const R = m.div(a) - - return loop(1, L, R) -} - -const Fe = (r, a, b, k, m) => { - const c = fe(r, a, b, m) - return ( - c.lt(k) - ? c - : fe(r, a, b, c) - ) -} - -const feis = arg => - Fe(4, u_a, u_b, u_c, new BN(arg)) - -module.exports = { - eff, - emm, - fe, - Fe, - feis -} -