Skip to content

Commit

Permalink
Fix issues with revert in commit 91eaf8b
Browse files Browse the repository at this point in the history
Signed-off-by: lovesh <[email protected]>
  • Loading branch information
lovesh committed Jul 7, 2024
1 parent 1693c71 commit 393d60b
Show file tree
Hide file tree
Showing 69 changed files with 983 additions and 195 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@docknetwork/crypto-wasm-ts",
"version": "0.63.0",
"version": "0.64.0",
"description": "Typescript abstractions over Dock's Rust crypto library's WASM wrapper",
"homepage": "https://github.com/docknetwork/crypto-wasm-ts",
"main": "lib/index.js",
Expand Down Expand Up @@ -34,7 +34,7 @@
"@types/flat": "^5.0.2",
"@types/lodash": "^4.14.195",
"bs58": "5.0.0",
"crypto-wasm-new": "npm:@docknetwork/crypto-wasm@0.30.0",
"crypto-wasm-new": "npm:@docknetwork/crypto-wasm@0.32.0",
"flat": "^5.0.2",
"json-pointer": "^0.6.2",
"json-stringify-deterministic": "^1.0.11",
Expand Down
21 changes: 20 additions & 1 deletion src/accumulator/params-and-keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import {
generateMembershipProvingKey,
generateNonMembershipProvingKey,
isAccumulatorParamsValid,
isAccumulatorPublicKeyValid
isAccumulatorPublicKeyValid,
generateAccumulatorParamsForKeyedVerification,
generateAccumulatorPublicKeyForKeyedVerification
} from 'crypto-wasm-new';

export class AccumulatorParams extends BytearrayWrapper {
Expand Down Expand Up @@ -117,3 +119,20 @@ export class NonMembershipProvingKey extends BytearrayWrapper {
return new MembershipProvingKey(accumulatorDeriveMembershipProvingKeyFromNonMembershipKey(this.value));
}
}

export class AccumulatorParamsForKeyedVerification extends BytearrayWrapper {
/**
* Generate accumulator parameters for keyed-verification.
* @param label - Pass to generate parameters deterministically.
* @returns
*/
static generate(label?: Uint8Array): AccumulatorParamsForKeyedVerification {
return new AccumulatorParamsForKeyedVerification(generateAccumulatorParamsForKeyedVerification(label));
}
}

export class AccumulatorPublicKeyForKeyedVerification extends BytearrayWrapper {
static generate(secretKey: AccumulatorSecretKey, params: AccumulatorParamsForKeyedVerification): AccumulatorPublicKeyForKeyedVerification {
return new AccumulatorPublicKeyForKeyedVerification(generateAccumulatorPublicKeyForKeyedVerification(secretKey.value, params.value));
}
}
15 changes: 13 additions & 2 deletions src/anonymous-credentials/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,19 @@ See these [tests](../../tests/anonymous-credentials/presentation.spec.ts) for ex

## Blinded Credentials

A user/holder can request a blinded credential from the signer/issuer where some of the attributes are not known to the signer. The blinded credential needs to be then unblinded, i.e. converted to a normal credential which can be verified by the signer's public key and used in presentations. The workflow to do this is as follows: user uses a [BlindedCredentialRequestBuilder](./blinded-credential-request-builder.ts) to create [BlindedCredentialRequest](./blinded-credential-request.ts) which is sent to the signer and subsequently verified by the signer. On successful verification, the signer uses `BlindedCredentialRequest` to create a [BlindedCredentialBuilder](./blinded-credential-builder.ts) to build a [BlindedCredential](./blinded-credential.ts). The `BlindedCredential` is sent to the user who then converts it to a normal credential. The `BlindedCredentialRequest` contains a `Presentation` inside which is verified by the signer.
The user while requesting such a credential might need to prove the possession of other credentials or prove that some of the blinded (hidden) attributes are same as the credentials in the presentation. The user can do this by calling methods on `BlindedCredentialRequestBuilder`, eg, calling `addCredentialToPresentation` will add a `Credential` already possessed by the user to the `Presentation` contained in the `BlindedCredentialRequest`, `enforceBoundsOnCredentialAttribute` will enforce bounds (min, max) on the credential attribute, etc. Any predicate supported in `Presentation`s can be proved over the credential added in `BlindedCredentialRequest`. Predicates can also be proven over the blinded attributes, eg, `markBlindedAttributesEqual` can be used to prove some blinded attribute equal to a credential attribute, `verifiablyEncryptBlindedAttribute` can be used to verifiably encrypt a blinded attribute, etc.
A user/holder can request a blinded credential from the signer/issuer where some of the attributes are not known to the signer. The blinded
credential needs to be then unblinded, i.e. converted to a normal credential which can be verified by the signer's public key and used in presentations.
The workflow to do this is as follows: user uses a [BlindedCredentialRequestBuilder](./blinded-credential-request-builder.ts) to create [BlindedCredentialRequest](./blinded-credential-request.ts) which is sent
to the signer and subsequently verified by the signer. On successful verification, the signer uses `BlindedCredentialRequest` to create
a [BlindedCredentialBuilder](./blinded-credential-builder.ts) to build a [BlindedCredential](./blinded-credential.ts). The `BlindedCredential` is sent to the user who then converts it to a
normal credential. The `BlindedCredentialRequest` contains a `Presentation` inside which is verified by the signer.
The user while requesting such a credential might need to prove the possession of other credentials or prove that some of the
blinded (hidden) attributes are same as the credentials in the presentation. The user can do this by calling methods
on `BlindedCredentialRequestBuilder`, eg, calling `addCredentialToPresentation` will add a `Credential` already possessed by
the user to the `Presentation` contained in the `BlindedCredentialRequest`, `enforceBoundsOnCredentialAttribute` will enforce bounds (min, max)
on the credential attribute, etc. Any predicate supported in `Presentation`s can be proved over the credential added in `BlindedCredentialRequest`.
Predicates can also be proven over the blinded attributes, eg, `markBlindedAttributesEqual` can be used to prove some blinded attribute equal to a
credential attribute, `verifiablyEncryptBlindedAttribute` can be used to verifiably encrypt a blinded attribute, etc.

See these [tests](../../tests/anonymous-credentials/blind-issuance.spec.ts) for examples of using these predicates.

Expand Down
2 changes: 1 addition & 1 deletion src/anonymous-credentials/blinded-credential-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export abstract class BlindedCredentialBuilder extends CredentialBuilderCommon {
knownAttributes = {...knownAttributes, ...this.blindedCredReq.unBlindedAttributes};
}
const encodedAttributes = new Map<number, Uint8Array>();
Object.entries(schema.encoder.encodeMessageObjectAsObject(knownAttributes)).forEach(([name, value]) => {
Object.entries(schema.encoder.encodeMessageObjectAsObjectConstantTime(knownAttributes)).forEach(([name, value]) => {
encodedAttributes.set(flattenedSchema[0].indexOf(name), value);
});
return [flattenedSchema[0].length, encodedAttributes];
Expand Down
12 changes: 6 additions & 6 deletions src/anonymous-credentials/blinded-credential-request-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ type Credential = BBSCredential | BBSPlusCredential | PSCredential;
export abstract class BlindedCredentialRequestBuilder<SigParams> extends Versioned {
// NOTE: Follows semver and must be updated accordingly when the logic of this class changes or the
// underlying crypto changes.
static VERSION = '0.4.0';
static VERSION = '0.5.0';

// The schema of the whole (unblinded credential). This should include all attributes, i.e. blinded and unblinded
_schema?: CredentialSchema;
Expand Down Expand Up @@ -500,7 +500,7 @@ export abstract class BlindedCredentialRequestBuilder<SigParams> extends Version
attrs[k] = v;
}
// Encode the blinded attributes
for (const [name, value] of schema.encoder.encodeMessageObjectAsMap(attrs).entries()) {
for (const [name, value] of schema.encoder.encodeMessageObjectAsMapConstantTime(attrs).entries()) {
const index = flattenedSchema[0].indexOf(name);
encodedAttributes.set(index, value);
attrNameToIndex.set(name, index);
Expand All @@ -511,7 +511,7 @@ export abstract class BlindedCredentialRequestBuilder<SigParams> extends Version
if (this._statusToBlind !== undefined) {
const name = `${STATUS_STR}.${REV_ID_STR}`;
const index = flattenedSchema[0].indexOf(name);
encodedAttributes.set(index, schema.encoder.encodeMessage(name, this._statusToBlind[REV_ID_STR]));
encodedAttributes.set(index, schema.encoder.encodeMessageConstantTime(name, this._statusToBlind[REV_ID_STR]));
attrNameToIndex.set(name, index);
attributesWithoutVals[name] = null;
unBlindedAttributes = {
Expand Down Expand Up @@ -560,7 +560,7 @@ export class BBSBlindedCredentialRequestBuilder extends BlindedCredentialRequest
): Uint8Array {
const sigParams = BBSSignatureParams.getSigParamsOfRequiredSize(totalAttributes, labelOrParams);
this.sigParams = sigParams;
return sigParams.commitToMessages(encodedSubject, false);
return sigParams.commitToMessagesConstantTime(encodedSubject, false);
}

/**
Expand Down Expand Up @@ -618,7 +618,7 @@ export class BBSPlusBlindedCredentialRequestBuilder extends BlindedCredentialReq
): Uint8Array {
const sigParams = BBSPlusSignatureParamsG1.getSigParamsOfRequiredSize(totalAttributes, labelOrParams);
this.sigParams = sigParams;
const [commitment] = sigParams.commitToMessages(encodedSubject, false, this.blinding);
const [commitment] = sigParams.commitToMessagesConstantTime(encodedSubject, false, this.blinding);
return commitment;
}

Expand Down Expand Up @@ -660,7 +660,7 @@ export class BBDT16BlindedCredentialRequestBuilder extends BlindedCredentialRequ
): Uint8Array {
const sigParams = BBDT16MacParams.getMacParamsOfRequiredSize(totalAttributes, labelOrParams);
this.sigParams = sigParams;
const [commitment] = sigParams.commitToMessages(encodedSubject, false, this.blinding);
const [commitment] = sigParams.commitToMessagesConstantTime(encodedSubject, false, this.blinding);
return commitment;
}

Expand Down
2 changes: 1 addition & 1 deletion src/anonymous-credentials/credential-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export abstract class CredentialBuilder<
> extends CredentialBuilderCommon {
// NOTE: Follows semver and must be updated accordingly when the logic of this class changes or the
// underlying crypto changes.
static VERSION = '0.6.0';
static VERSION = '0.7.0';

_encodedAttributes?: { [key: string]: Uint8Array };
_sig?: Signature;
Expand Down
16 changes: 10 additions & 6 deletions src/anonymous-credentials/presentation-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ type Credential = BBSCredential | BBSPlusCredential | PSCredential | BBDT16Crede
export class PresentationBuilder extends Versioned {
// NOTE: Follows semver and must be updated accordingly when the logic of this class changes or the
// underlying crypto changes.
static VERSION = '0.8.0';
static VERSION = '0.9.0';

// This can specify the reason why the proof was created, or date of the proof, or self-attested attributes (as JSON string), etc
_context?: string;
Expand Down Expand Up @@ -561,17 +561,20 @@ export class PresentationBuilder extends Versioned {
revealedNames.add(`${STATUS_STR}.${REV_CHECK_STR}`);
}

const useConstantTimeEncoding = semver.gte(cred.version, '0.6.0');
const [revealedAttrsEncoded, unrevealedAttrsEncoded, revealedAtts] = getRevealedAndUnrevealed(
cred.serializeForSigning(),
revealedNames,
schema.encoder
schema.encoder,
useConstantTimeEncoding
);
const statement = buildSignatureProverStatementFromParamsRef(
setupParamsTrk,
sigParams,
numAttribs,
revealedAttrsEncoded,
this.credentials[credIndex][1]
this.credentials[credIndex][1],
useConstantTimeEncoding
);
const witness = buildWitness(cred.signature, unrevealedAttrsEncoded);
statements.add(statement);
Expand All @@ -590,11 +593,12 @@ export class PresentationBuilder extends Versioned {
accumulated: s[1],
extra: s[3]
};
const encodedRevId = useConstantTimeEncoding ? schema.encoder.encodeMessageConstantTime(`${STATUS_STR}.${REV_ID_STR}`, cred.credentialStatus[REV_ID_STR]) : schema.encoder.encodeMessage(`${STATUS_STR}.${REV_ID_STR}`, cred.credentialStatus[REV_ID_STR]);
credStatusAux.push([
credIndex,
cred.credentialStatus[TYPE_STR],
cred.credentialStatus[REV_CHECK_STR],
schema.encoder.encodeMessage(`${STATUS_STR}.${REV_ID_STR}`, cred.credentialStatus[REV_ID_STR])
encodedRevId
]);
}

Expand Down Expand Up @@ -637,7 +641,7 @@ export class PresentationBuilder extends Versioned {
// @ts-ignore
attributeIneqs[name].push(ineq_j[0]);
// Encode the public value
ineq_j[1] = schema.encoder.encodeMessage(name, ineq_j[0].inEqualTo);
ineq_j[1] = schema.encoder.encodeMessageConstantTime(name, ineq_j[0].inEqualTo);
});
updateEncodedAttrs(name, encodedAttrs);
}
Expand Down Expand Up @@ -1201,7 +1205,7 @@ export class PresentationBuilder extends Versioned {
v.forEach((v_j) => {
arr.push(v_j[0]);
// @ts-ignore
v_j[1] = this.blindCredReq?.req?.schema.encoder.encodeMessage(k, v_j[0].inEqualTo);
v_j[1] = this.blindCredReq?.req?.schema.encoder?.encodeMessageConstantTime(k, v_j[0].inEqualTo);
});
m.set(k, arr);
}
Expand Down
21 changes: 13 additions & 8 deletions src/anonymous-credentials/presentation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ export class Presentation extends Versioned {
const setupParamsTrk = new SetupParamsTracker();
const sigParamsByScheme = new Map();

const versionGt6 = semver.gt(this.version, '0.6.0');
const presVersionGt6 = semver.gt(this.version, '0.6.0');

for (let credIndex = 0; credIndex < this.spec.credentials.length; credIndex++) {
const presentedCred = this.spec.credentials[credIndex];
Expand All @@ -223,12 +223,14 @@ export class Presentation extends Versioned {
const flattenedSchema = presentedCredSchema.flatten();
const numAttribs = flattenedSchema[0].length;

const useConstantTimeEncoding = semver.gte(presentedCred.version, '0.6.0');
const revealedEncoded = Presentation.encodeRevealed(
credIndex,
presentedCred,
presentedCredSchema,
flattenedSchema[0],
versionGt6
presVersionGt6,
useConstantTimeEncoding
);

let sigParamsClass;
Expand Down Expand Up @@ -268,6 +270,7 @@ export class Presentation extends Versioned {
numAttribs,
revealedEncoded,
credVerifParams.get(credIndex),
semver.gt(this._version, '0.7.0')
);
statements.add(statement);
flattenedSchemas.push(flattenedSchema);
Expand All @@ -289,7 +292,7 @@ export class Presentation extends Versioned {
obj[names[j]] = ineqs[j].map((ineqs_j) => [
ineqs_j,
// @ts-ignore
presentedCredSchema.encoder.encodeMessage(names[j], ineqs_j.inEqualTo)
presentedCredSchema.encoder.encodeMessageConstantTime(names[j], ineqs_j.inEqualTo)
]);
}
ineqsAux.push([credIndex, obj]);
Expand Down Expand Up @@ -650,7 +653,7 @@ export class Presentation extends Versioned {
obj[names[j]] = ineqs[j].map((ineqs_j) => [
ineqs_j,
// @ts-ignore
this.spec.blindCredentialRequest.schema.encoder.encodeMessage(names[j], ineqs_j.inEqualTo)
this.spec.blindCredentialRequest.schema.encoder.encodeMessageConstantTime(names[j], ineqs_j.inEqualTo)
]);
}
this.processAttributeInequalities(
Expand Down Expand Up @@ -830,14 +833,16 @@ export class Presentation extends Versioned {
* @param presentedCred
* @param presentedCredSchema
* @param flattenedNames
* @param newVersion
* @param presVersionGt6
* @param useConstantTimeEncoding
*/
private static encodeRevealed(
credIdx: number,
presentedCred: IPresentedCredential,
presentedCredSchema: CredentialSchema,
flattenedNames: string[],
newVersion: boolean
presVersionGt6: boolean,
useConstantTimeEncoding = true
): Map<number, Uint8Array> {
const revealedRaw = _.cloneDeep(presentedCred.revealedAttributes) as object;
revealedRaw[CRYPTO_VERSION_STR] = presentedCred.version;
Expand All @@ -861,7 +866,7 @@ export class Presentation extends Versioned {
[ID_STR]: presentedCred.status[ID_STR],
[REV_CHECK_STR]: presentedCred.status[REV_CHECK_STR]
};
if (newVersion) {
if (presVersionGt6) {
revealedRaw[STATUS_STR][TYPE_STR] = presentedCred.status[TYPE_STR];
}
}
Expand All @@ -876,7 +881,7 @@ export class Presentation extends Versioned {
throw new Error(`Attribute name ${k} not found in schema`);
}
} else {
encoded.set(i, presentedCredSchema.encoder.encodeMessage(k, v));
encoded.set(i, useConstantTimeEncoding ? presentedCredSchema.encoder.encodeMessageConstantTime(k, v) : presentedCredSchema.encoder.encodeMessage(k, v));
}
});
return encoded;
Expand Down
17 changes: 11 additions & 6 deletions src/anonymous-credentials/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@ export type CredVal = string | number | object | CredVal[];
export class CredentialSchema extends Versioned {
// NOTE: Follows semver and must be updated accordingly when the logic of this class changes or the
// underlying crypto changes.
static VERSION = '0.4.0';
static VERSION = '0.5.0';

private static readonly STR_TYPE = 'string';
private static readonly STR_REV_TYPE = 'stringReversible';
Expand Down Expand Up @@ -513,13 +513,15 @@ export class CredentialSchema extends Versioned {
* when deserializing to get the exact object that was serialized which is necessary when verifying signatures
* @param overrides - Override any properties of the schema
* @param fullJsonSchema - When `jsonSchema` does not contain the properties, this object is expected to contain them.
* @param useConstantTimeEncoder
*/
constructor(
jsonSchema: IEmbeddedJsonSchema | IJsonSchema,
parsingOpts: Partial<ISchemaParsingOpts> = DefaultSchemaParsingOpts,
addMissingParsingOpts = true,
overrides?: Partial<ISchemaOverrides>,
fullJsonSchema?: IEmbeddedJsonSchema
fullJsonSchema?: IEmbeddedJsonSchema,
useConstantTimeEncoder = true
) {
// This functions flattens schema object twice but the repetition can be avoided. Keeping this deliberately for code clarity.
let pOpts;
Expand Down Expand Up @@ -552,14 +554,14 @@ export class CredentialSchema extends Versioned {
this.jsonSchema = jsonSchema;
this.parsingOptions = pOpts;
this.fullJsonSchema = fullJsonSchema;
this.initEncoder();
this.initEncoder(useConstantTimeEncoder);
}

/**
* Initialize the encoder as per the internal representation of schema, i.e. `ISchema`
*/
initEncoder() {
const defaultEncoder = Encoder.defaultEncodeFunc();
initEncoder(useConstantTimeEncoder = true) {
const defaultEncoder = useConstantTimeEncoder ? Encoder.defaultEncodeFuncConstantTime() : Encoder.defaultEncodeFunc();
const encoders = new Map<string, EncodeFunc>();
const [names, values] = this.flatten();
for (let i = 0; i < names.length; i++) {
Expand Down Expand Up @@ -588,6 +590,7 @@ export class CredentialSchema extends Versioned {
f = Encoder.decimalNumberEncoder(value['minimum'], value['decimalPlaces']);
break;
default:
// For other types including string type, use default encoder
f = defaultEncoder;
}
encoders.set(names[i], f);
Expand Down Expand Up @@ -854,11 +857,13 @@ export class CredentialSchema extends Versioned {
}
}
}
// For older version, a variable time message encoder was mistakenly used
const useConstantTimeEncoder = semver.gte(version, '0.5.0');
// Note: `parsingOptions` might still be in an incorrect format which can fail the next call
// Note: Passing `addMissingParsingOpts` as false to recreate the exact same object that was serialized. This is important
// when verifying signatures.
// @ts-ignore
return new CredentialSchema(jsonSchema, parsingOptions, false, { version: version }, full);
return new CredentialSchema(jsonSchema, parsingOptions, false, { version }, full, useConstantTimeEncoder);
}

/**
Expand Down
Loading

0 comments on commit 393d60b

Please sign in to comment.