Skip to content

Commit b8194f9

Browse files
committed
Fix empty objects in credential throws error
Signed-off-by: Samuel Hellawell <[email protected]>
1 parent f6e26c3 commit b8194f9

File tree

5 files changed

+42
-14
lines changed

5 files changed

+42
-14
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@docknetwork/crypto-wasm-ts",
3-
"version": "0.31.2",
3+
"version": "0.31.3",
44
"description": "Typescript abstractions over Dock's Rust crypto library's WASM wrapper",
55
"homepage": "https://github.com/docknetwork/crypto-wasm-ts",
66
"main": "lib/index.js",

src/anonymous-credentials/schema.ts

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,7 @@ export class CredentialSchema extends Versioned {
544544

545545
static validateGeneric(schema: object, ignoreKeys: Set<string> = new Set()) {
546546
const [names, values] = this.flattenSchemaObj(schema);
547+
547548
for (let i = 0; i < names.length; i++) {
548549
if (ignoreKeys.has(names[i])) {
549550
continue;
@@ -644,16 +645,16 @@ export class CredentialSchema extends Versioned {
644645
properties: {
645646
id: {
646647
type: 'string'
647-
},
648-
},
648+
}
649+
}
649650
},
650651
proof: {
651652
type: 'object',
652653
properties: {
653654
type: {
654655
type: 'string'
655-
},
656-
},
656+
}
657+
}
657658
}
658659
}
659660
};
@@ -1101,13 +1102,20 @@ export class CredentialSchema extends Versioned {
11011102
} else if (schemaProps[key]['type'] == 'object' && typ == 'object') {
11021103
const schemaKeys = new Set([...Object.keys(schemaProps[key]['properties'])]);
11031104
const valKeys = new Set([...Object.keys(value)]);
1104-
for (const vk of valKeys) {
1105-
CredentialSchema.generateFromCredential(value, schemaProps[key]['properties']);
1106-
}
1107-
// Delete extra keys not in cred
1108-
for (const sk of schemaKeys) {
1109-
if (value[sk] === undefined) {
1110-
delete schemaKeys[sk];
1105+
1106+
// If empty object, skip it here otherwise causes problems downstream
1107+
if (schemaKeys.size === 0) {
1108+
delete schemaProps[key];
1109+
} else {
1110+
for (const vk of valKeys) {
1111+
// TODO: why this loop? seems useless?
1112+
CredentialSchema.generateFromCredential(value, schemaProps[key]['properties']);
1113+
}
1114+
// Delete extra keys not in cred
1115+
for (const sk of schemaKeys) {
1116+
if (value[sk] === undefined) {
1117+
delete schemaKeys[sk];
1118+
}
11111119
}
11121120
}
11131121
} else {

src/anonymous-credentials/util.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import { ValueType, ValueTypes } from './schema';
3232
import { Encoder } from '../bbs-plus';
3333
import { SetupParam, Statement, WitnessEqualityMetaStatement } from '../composite-proof';
3434
import { SetupParamsTracker } from './setup-params-tracker';
35+
import { isEmptyObject } from '../util';
3536

3637
export function dockAccumulatorParams(): AccumulatorParams {
3738
return Accumulator.generateParams(ACCUMULATOR_PARAMS_LABEL_BYTES);
@@ -56,7 +57,8 @@ export function dockSaverEncryptionGensUncompressed(): SaverEncryptionGensUncomp
5657
export function flattenTill2ndLastKey(obj: object): [string[], object[]] {
5758
const flattened = {};
5859
const temp = flatten(obj) as object;
59-
for (const k of Object.keys(temp)) {
60+
const tempKeys = Object.keys(temp).filter((key) => typeof temp[key] !== 'object' || !isEmptyObject(temp[key]));
61+
for (const k of tempKeys) {
6062
// taken from https://stackoverflow.com/a/5555607
6163
const pos = k.lastIndexOf('.');
6264
const name = k.substring(0, pos);

src/util.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,12 @@ export function randomFieldElement(seed?: Uint8Array): Uint8Array {
6969
*/
7070
export function flattenObjectToKeyValuesList(obj: object, flattenOptions = undefined): [string[], unknown[]] {
7171
const flattened = flatten(obj, flattenOptions) as object;
72-
const keys = Object.keys(flattened).sort();
72+
73+
// Sort and filter keys to remove empty objects
74+
// this is done because schema generation removes empty objects + nothing to encode
75+
const keys = Object.keys(flattened)
76+
.sort()
77+
.filter((k) => typeof flattened[k] !== 'object' || !isEmptyObject(flattened[k]));
7378
// @ts-ignore
7479
const values = keys.map((k) => flattened[k]);
7580
return [keys, values];

tests/anonymous-credentials/credential.spec.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -871,4 +871,17 @@ describe('Credential signing and verification', () => {
871871
checkResult(recreatedCred.verify(pk));
872872
}
873873
});
874+
875+
it('for credential with auto-generated schema and empty objects', () => {
876+
const builder = new CredentialBuilder();
877+
builder.schema = new CredentialSchema(CredentialSchema.essential());
878+
builder.subject = {
879+
fname: 'John',
880+
emptyObject: {},
881+
lname: 'Smith',
882+
};
883+
884+
const cred = builder.sign(sk, undefined, {requireSameFieldsAsSchema: false});
885+
checkResult(cred.verify(pk));
886+
});
874887
});

0 commit comments

Comments
 (0)