commit c91e9175c1ee346af2eb8b90abc90202c96b9aac
parent 86d0d8e4dc7fe04d321ca18d42c68c6f60005dbf
Author: Jared Tobin <jared@jtobin.io>
Date: Sat, 10 Nov 2018 20:42:19 +1300
Merge pull request #15 from urbit/jt-padding
Preserve leading zeros bytes in patq2hex/hex2patq
Diffstat:
4 files changed, 105 insertions(+), 47 deletions(-)
diff --git a/package.json b/package.json
@@ -1,6 +1,6 @@
{
"name": "urbit-ob",
- "version": "3.0.0",
+ "version": "3.0.1",
"description": "Utilities for Hoon-style atom printing and conversion",
"main": "src/index.js",
"scripts": {
diff --git a/src/index.js b/src/index.js
@@ -2,40 +2,8 @@
const co = require('./internal/co')
const ob = require('./internal/ob')
-/**
- * Remove all leading zero bytes from a hex-encoded string.
- * @param {string} str a hex encoded string
- * @return {string}
- */
-const removeLeadingZeroBytes = str =>
- str.slice(0, 2) === '00'
- ? removeLeadingZeroBytes(str.slice(2))
- : str
-
-/**
- * Equality comparison, modulo leading zero bytes.
- * @param {string} s a hex-encoded string
- * @param {string} t a hex-encoded string
- * @return {bool}
- */
-const eqModLeadingZeroBytes = (s, t) =>
- removeLeadingZeroBytes(s) === removeLeadingZeroBytes(t)
-
-/**
- * Equality comparison on @q values.
- * @param {string} p a @q-encoded string
- * @param {string} q a @q-encoded string
- * @return {bool}
- */
-const eqPatq = (p, q) => {
- const phex = co.patq2hex(p)
- const qhex = co.patq2hex(q)
- return eqModLeadingZeroBytes(phex, qhex)
-}
-
module.exports = Object.assign(
co,
- ob,
- { eqPatq }
+ ob
)
diff --git a/src/internal/co.js b/src/internal/co.js
@@ -126,6 +126,15 @@ const hex2patp = (hex) =>
patp(new BN(hex, 'hex'))
/**
+ * Convert a Buffer to a @p-encoded string.
+ *
+ * @param {Buffer} buf
+ * @return {String}
+ */
+const buf2patp = (buf) =>
+ hex2patp(buf.toString('hex'))
+
+/**
* Convert a @p-encoded string to a hex-encoded string.
*
* @param {String} name @p
@@ -147,10 +156,22 @@ const patp2hex = (name) => {
'')
const bn = new BN(addr, 2)
- return ob.fend(bn).toString('hex')
+ const hex = ob.fend(bn).toString('hex')
+ return hex.length % 2 !== 0
+ ? hex.padStart(hex.length + 1, '0')
+ : hex
}
/**
+ * Convert a @p-encoded string to a Buffer.
+ *
+ * @param {String} name
+ * @return {Buffer}
+ */
+const patp2buf = name =>
+ Buffer.from(patp2hex(name), 'hex')
+
+/**
* Convert a @p-encoded string to a bignum.
*
* @param {String} name @p
@@ -175,10 +196,18 @@ const patp2dec = name =>
* @return {String}
*/
const patq = (arg) => {
- const n = new BN(arg)
-
- const buf = n.toArrayLike(Buffer)
+ const bn = new BN(arg)
+ const buf = bn.toArrayLike(Buffer)
+ return buf2patq(buf)
+}
+/**
+ * Convert a Buffer into a @q-encoded string.
+ *
+ * @param {Buffer} buf
+ * @return {String}
+ */
+const buf2patq = buf => {
const chunked =
buf.length % 2 !== 0 && buf.length > 1
? lodash.concat([[buf[0]]], lodash.chunk(buf.slice(1), 2))
@@ -206,11 +235,20 @@ const patq = (arg) => {
/**
* Convert a hex-encoded string to a @q-encoded string.
*
+ * Note that this preserves leading zero bytes.
+ *
* @param {String} hex
* @return {String}
*/
-const hex2patq = hex =>
- patq(new BN(hex, 'hex'))
+const hex2patq = arg => {
+ const hex =
+ arg.length % 2 !== 0
+ ? arg.padStart(arg.length + 1, '0')
+ : arg
+
+ const buf = Buffer.from(hex, 'hex')
+ return buf2patq(buf)
+}
/**
* Convert a @q-encoded string to a hex-encoded string.
@@ -251,6 +289,17 @@ const patq2bn = name =>
new BN(patq2hex(name), 'hex')
/**
+ * Convert a @q-encoded string to a Buffer.
+ *
+ * @param {String} name @q
+ * @return {Buffer}
+ */
+const patq2buf = name => {
+ const hex = patq2hex(name)
+ return Buffer.from(hex, 'hex')
+}
+
+/**
* Convert a @q-encoded string to a decimal-encoded string.
*
* @param {String} name @q
@@ -328,15 +377,47 @@ const isValidPat = name => {
return leadingTilde && !wrongLength && sylsExist
}
+/**
+ * Remove all leading zero bytes from a sliceable value.
+ * @param {String, Buffer, Array}
+ * @return {String}
+ */
+const removeLeadingZeroBytes = str =>
+ str.slice(0, 2) === '00'
+ ? removeLeadingZeroBytes(str.slice(2))
+ : str
+
+/**
+ * Equality comparison, modulo leading zero bytes.
+ * @param {String, Buffer, Array}
+ * @param {String, Buffer, Array}
+ * @return {Bool}
+ */
+const eqModLeadingZeroBytes = (s, t) =>
+ lodash.isEqual(removeLeadingZeroBytes(s), removeLeadingZeroBytes(t))
+
+/**
+ * Equality comparison on @q values.
+ * @param {String} p a @q-encoded string
+ * @param {String} q a @q-encoded string
+ * @return {Bool}
+ */
+const eqPatq = (p, q) => {
+ const phex = patq2hex(p)
+ const qhex = patq2hex(q)
+ return eqModLeadingZeroBytes(phex, qhex)
+}
+
module.exports = {
patp,
patp2hex,
- patp2dec,
hex2patp,
+ patp2dec,
patq,
patq2hex,
- patq2dec,
hex2patq,
+ patq2dec,
clan,
- sein
+ sein,
+ eqPatq
}
diff --git a/test/co.test.js b/test/co.test.js
@@ -1,17 +1,18 @@
const BN = require('bn.js')
-const { expect } = require('chai');
+const { expect } = require('chai')
const jsc = require('jsverify')
const {
patp,
patp2hex,
- patp2dec,
hex2patp,
+ patp2dec,
patq,
patq2hex,
- patq2dec,
hex2patq,
+ patq2dec,
clan,
- sein
+ sein,
+ eqPatq
} = require('../src/internal/co')
const patps = jsc.uint32.smap(
@@ -190,3 +191,11 @@ describe('clan/sein', () => {
})
+describe('eqPatq', () => {
+ it('works as expected', () => {
+ expect(eqPatq('~dozzod-dozzod', '~zod')).to.equal(true)
+ expect(eqPatq('~dozzod-mardun', '~mardun')).to.equal(true)
+ expect(eqPatq('~dozzod-mardun', '~mardun-dozzod')).to.equal(false)
+ })
+})
+