Skip to content

Commit

Permalink
Change "URDNA2015" to "RDFC-1.0" to match spec.
Browse files Browse the repository at this point in the history
**BREAKING**: Change "URDNA2015" to "RDFC-1.0" to match latest spec
changes. Use of "URDNA2015" as a named algorithm option is now
deprecated and will cause a warning.
  • Loading branch information
davidlehn committed Jun 22, 2023
1 parent 6a413f5 commit 310a9aa
Show file tree
Hide file tree
Showing 10 changed files with 58 additions and 24 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
Any calling code that was passing in an incorrect value needs to be fixed.

### Changed
- **BREAKING**: Change "URDNA2015" to "RDFC-1.0" to match spec changes. Use of
"URDNA2015" as a named algorithm option is now deprecated and will cause a
warning.
- **BREAKING**: Use `globalThis` to access `crypto` in browsers. Use a polyfill
if your environment doesn't support `globalThis`.
- Update tooling.
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,12 @@ const dataset = {
};

// canonize a data set with a particular algorithm with async/await
const canonical = await canonize.canonize(dataset, {algorithm: 'URDNA2015'});
const canonical = await canonize.canonize(dataset, {algorithm: 'RDFC-1.0'});

// canonize a data set with a particular algorithm and force use of the
// native implementation
const canonical = await canonize.canonize(dataset, {
algorithm: 'URDNA2015',
algorithm: 'RDFC-1.0',
useNative: true
});
```
Expand Down
2 changes: 1 addition & 1 deletion bench-nsolid.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ const KEYS = ['subject', 'predicate', 'object', 'graph'];
//const count = 1000000; // ~30 secs
for(let i = 0; i < count; ++i) {
/*const result = */await canonize(quads, {
algorithm: 'URDNA2015',
algorithm: 'RDFC-1.0',
usePureJavaScript: true
});
//console.log(result);
Expand Down
6 changes: 3 additions & 3 deletions lib/URDNA2015.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ module.exports = class URDNA2015 {
canonicalIdMap = new Map(),
maxDeepIterations = Infinity
} = {}) {
this.name = 'URDNA2015';
this.name = 'RDFC-1.0';
this.blankNodeInfo = new Map();
this.canonicalIssuer = new IdentifierIssuer('_:c14n', canonicalIdMap);
this.createMessageDigest = createMessageDigest;
Expand Down Expand Up @@ -47,7 +47,7 @@ module.exports = class URDNA2015 {

// 4) `simple` flag is skipped -- loop is optimized away. This optimization
// is permitted because there was a typo in the hash first degree quads
// algorithm in the URDNA2015 spec that was implemented widely making it
// algorithm in the RDFC-1.0 spec that was implemented widely making it
// such that it could not be fixed; the result was that the loop only
// needs to be run once and the first degree quad hashes will never change.
// 5.1-5.2 are skipped; first degree quad hashes are generated just once
Expand Down Expand Up @@ -393,7 +393,7 @@ module.exports = class URDNA2015 {
if(component.termType !== 'BlankNode') {
return component;
}
/* Note: A mistake in the URDNA2015 spec that made its way into
/* Note: A mistake in the RDFC-1.0 spec that made its way into
implementations (and therefore must stay to avoid interop breakage)
resulted in an assigned canonical ID, if available for
`component.value`, not being used in place of `_:a`/`_:z`, so
Expand Down
6 changes: 3 additions & 3 deletions lib/URDNA2015Sync.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ module.exports = class URDNA2015Sync {
canonicalIdMap = new Map(),
maxDeepIterations = Infinity
} = {}) {
this.name = 'URDNA2015';
this.name = 'RDFC-1.0';
this.blankNodeInfo = new Map();
this.canonicalIssuer = new IdentifierIssuer('_:c14n', canonicalIdMap);
this.createMessageDigest = createMessageDigest;
Expand Down Expand Up @@ -48,7 +48,7 @@ module.exports = class URDNA2015Sync {

// 4) `simple` flag is skipped -- loop is optimized away. This optimization
// is permitted because there was a typo in the hash first degree quads
// algorithm in the URDNA2015 spec that was implemented widely making it
// algorithm in the RDFC-1.0 spec that was implemented widely making it
// such that it could not be fixed; the result was that the loop only
// needs to be run once and the first degree quad hashes will never change.
// 5.1-5.2 are skipped; first degree quad hashes are generated just once
Expand Down Expand Up @@ -384,7 +384,7 @@ module.exports = class URDNA2015Sync {
if(component.termType !== 'BlankNode') {
return component;
}
/* Note: A mistake in the URDNA2015 spec that made its way into
/* Note: A mistake in the RDFC-1.0 spec that made its way into
implementations (and therefore must stay to avoid interop breakage)
resulted in an assigned canonical ID, if available for
`component.value`, not being used in place of `_:a`/`_:z`, so
Expand Down
19 changes: 13 additions & 6 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@

const URDNA2015 = require('./URDNA2015');
const URDNA2015Sync = require('./URDNA2015Sync');
const {warning} = require('./platform');

// optional native support
let rdfCanonizeNative;
Expand Down Expand Up @@ -83,7 +84,7 @@ exports._rdfCanonizeNative = function(api) {
* @param {Array|object|string} input - The input to canonize given as a
* dataset, legacy dataset, or format specified by 'inputFormat' option.
* @param {object} options - The options to use:
* {string} algorithm - The canonicalization algorithm to use, `URDNA2015`.
* {string} algorithm - The canonicalization algorithm to use, `RDFC-1.0`.
* {Function} [createMessageDigest] - A factory function for creating a
* `MessageDigest` interface that overrides the built-in message digest
* implementation used by the canonize algorithm; note that using a hash
Expand All @@ -98,7 +99,7 @@ exports._rdfCanonizeNative = function(api) {
* {boolean} [useNative=false] - Use native implementation.
* {number} [maxDeepIterations=Infinity] - The maximum number of times to run
* deep comparison algorithms (such as the N-Degree Hash Quads algorithm
* used in URDNA2015) before bailing out and throwing an error; this is a
* used in RDFC-1.0) before bailing out and throwing an error; this is a
* useful setting for preventing wasted CPU cycles or DoS when canonizing
* meaningless or potentially malicious datasets, a recommended value is
* `1`.
Expand All @@ -121,7 +122,10 @@ exports.canonize = async function(input, options) {
err ? reject(err) : resolve(canonical)));
}

if(options.algorithm === 'URDNA2015') {
if(['RDFC-1.0', 'URDNA2015'].includes(options.algorithm)) {
if(options.algorithm === 'URDNA2015') {
warning('"URDNA2015" algorithm is deprecated in favor of "RDFC-1.0"');
}
return new URDNA2015(options).main(dataset);
}
if(!('algorithm' in options)) {
Expand All @@ -139,7 +143,7 @@ exports.canonize = async function(input, options) {
* @param {Array|object|string} input - The input to canonize given as a
* dataset, legacy dataset, or format specified by 'inputFormat' option.
* @param {object} options - The options to use:
* {string} algorithm - The canonicalization algorithm to use, `URDNA2015`.
* {string} algorithm - The canonicalization algorithm to use, `RDFC-1.0`.
* {Function} [createMessageDigest] - A factory function for creating a
* `MessageDigest` interface that overrides the built-in message digest
* implementation used by the canonize algorithm; note that using a hash
Expand All @@ -151,7 +155,7 @@ exports.canonize = async function(input, options) {
* {boolean} [useNative=false] - Use native implementation.
* {number} [maxDeepIterations=Infinity] - The maximum number of times to run
* deep comparison algorithms (such as the N-Degree Hash Quads algorithm
* used in URDNA2015) before bailing out and throwing an error; this is a
* used in RDFC-1.0) before bailing out and throwing an error; this is a
* useful setting for preventing wasted CPU cycles or DoS when canonizing
* meaningless or potentially malicious datasets, a recommended value is
* `1`.
Expand All @@ -171,7 +175,10 @@ exports._canonizeSync = function(input, options) {
}
return rdfCanonizeNative.canonizeSync(dataset, options);
}
if(options.algorithm === 'URDNA2015') {
if(['RDFC-1.0', 'URDNA2015'].includes(options.algorithm)) {
if(options.algorithm === 'URDNA2015') {
warning('"URDNA2015" algorithm is deprecated in favor of "RDFC-1.0"');
}
return new URDNA2015Sync(options).main(dataset);
}
if(!('algorithm' in options)) {
Expand Down
8 changes: 8 additions & 0 deletions lib/platform-browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,11 @@ exports.bufferToHex = function bufferToHex(buffer) {
}
return hex;
};

const seen = new Set();
exports.warning = function warning(msg) {
if(!seen.has(msg)) {
seen.add(msg);
console.warn(`WARNING[rdf-canonize]: ${msg}.`);
}
};
8 changes: 8 additions & 0 deletions lib/platform.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,11 @@ exports.crypto = crypto.webcrypto;
exports.bufferToHex = function bufferToHex(buffer) {
return Buffer.from(buffer).toString('hex');
};

const seen = new Set();
exports.warning = function warning(msg) {
if(!seen.has(msg)) {
seen.add(msg);
console.warn(`WARNING[rdf-canonize]: ${msg}.`);
}
};
15 changes: 11 additions & 4 deletions test/misc.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ describe('API tests', () => {
let error;
try {
await rdfCanonize.canonize('', {
algorithm: 'URDNA2015',
algorithm: 'RDFC-1.0',
inputFormat: 'application/bogus',
format: 'application/n-quads'
});
Expand All @@ -25,7 +25,7 @@ describe('API tests', () => {
let error;
try {
await rdfCanonize.canonize([], {
algorithm: 'URDNA2015',
algorithm: 'RDFC-1.0',
inputFormat: 'application/bogus',
format: 'application/n-quads'
});
Expand All @@ -39,7 +39,7 @@ describe('API tests', () => {
let error;
try {
await rdfCanonize.canonize({}, {
algorithm: 'URDNA2015',
algorithm: 'RDFC-1.0',
inputFormat: 'application/bogus',
format: 'application/n-quads'
});
Expand All @@ -65,12 +65,19 @@ _:c14n1 <urn:p1> "v1" .

const canonicalIdMap = new Map();
const output = await rdfCanonize.canonize(input, {
algorithm: 'URDNA2015',
algorithm: 'RDFC-1.0',
inputFormat: 'application/n-quads',
format: 'application/n-quads',
canonicalIdMap
});
assert.deepStrictEqual(output, expected);
assert.deepStrictEqual(canonicalIdMap, expectIdMap);
});

it('should warn when using URDNA2015', async () => {
await rdfCanonize.canonize({}, {
algorithm: 'URDNA2015',
format: 'application/n-quads'
});
});
});
11 changes: 6 additions & 5 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,11 +154,11 @@ const manifest = options.manifest || {
};

const TEST_TYPES = {
'rdfc:Urdna2015EvalTest': {
'rdfc:RDFC10EvalTest': {
params: [
parseNQuads(readTestNQuads('action')),
createTestOptions({
algorithm: 'URDNA2015',
algorithm: 'RDFC-1.0',
format: 'application/n-quads'
})
],
Expand Down Expand Up @@ -440,7 +440,7 @@ async function addTest(manifest, test, tests) {

// async native
if(doAsync && options.rdfCanonizeNative &&
testOptions.algorithm === 'URDNA2015') {
testOptions.algorithm === 'RDFC-1.0') {
jobTests.forEach(jobs => {
const _an_test = {
title: description + ` (asynchronous, native, jobs=${jobs})`,
Expand Down Expand Up @@ -508,7 +508,7 @@ async function addTest(manifest, test, tests) {

// sync native
if(doSync && options.rdfCanonizeNative &&
testOptions.algorithm === 'URDNA2015') {
testOptions.algorithm === 'RDFC-1.0') {
jobTests.forEach(jobs => {
const _sn_test = {
title: description + ` (synchronous, native, jobs=${jobs})`,
Expand Down Expand Up @@ -664,7 +664,8 @@ function makeFn({
}
} else if(isJsonLdType(test, 'XXX:PositiveEvaluationTest') ||
isJsonLdType(test, 'rdfc:Urgna2012EvalTest') ||
isJsonLdType(test, 'rdfc:Urdna2015EvalTest')) {
isJsonLdType(test, 'rdfc:Urdna2015EvalTest') ||
isJsonLdType(test, 'rdfc:RDFC10EvalTest')) {
if(err) {
throw err;
}
Expand Down

0 comments on commit 310a9aa

Please sign in to comment.