Skip to content

Commit

Permalink
feat: implemented credentialDeployment
Browse files Browse the repository at this point in the history
  • Loading branch information
GuilaneDen committed Dec 10, 2024
1 parent de39666 commit 3499e0e
Show file tree
Hide file tree
Showing 5 changed files with 174 additions and 19 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
submodules: true
- name: Install node
uses: actions/setup-node@v2
uses: actions/setup-node@v3
with:
node-version: '16'
registry-url: "https://registry.npmjs.org/"
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 14 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,31 +1,34 @@
{
"name": "@ledgerhq/hw-app-algorand",
"name": "@ledgerhq/hw-app-concordium",
"type": "module",
"version": "6.29.4",
"description": "Ledger Hardware Wallet Algorand Application API",
"description": "Ledger Hardware Wallet Concordium Application API",
"keywords": [
"Ledger",
"LedgerWallet",
"algo",
"Algorand",
"NanoS",
"CCD",
"Concordium",
"NanoS+",
"NanoX",
"Flex",
"Stax",
"Blue",
"Hardware Wallet"
],
"repository": {
"type": "git",
"url": "https://github.com/LedgerHQ/ledger-live.git"
"url": "https://github.com/blooo-io/hw-app-concordium.git"
},
"bugs": {
"url": "https://github.com/LedgerHQ/ledger-live/issues"
"url": "https://github.com/blooo-io/hw-app-concordium/issues"
},
"homepage": "https://github.com/LedgerHQ/ledger-live/tree/develop/libs/ledgerjs/packages/hw-app-algorand",
"homepage": "https://github.com/blooo-io/hw-app-concordium",
"publishConfig": {
"access": "public"
},
"main": "lib/Algorand.js",
"module": "lib-es/Algorand.js",
"types": "lib/Algorand.d.ts",
"main": "lib/Concordium.js",
"module": "lib-es/Concordium.js",
"types": "lib/Concordium.d.ts",
"license": "Apache-2.0",
"dependencies": {
"@concordium/common-sdk": "^9.5.3",
Expand Down
110 changes: 107 additions & 3 deletions src/Concordium.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ import {
serializeInitContract,
serializeUpdateContract,
serializeTransactionPayloads,
serializeUpdateCredentials
serializeUpdateCredentials,
serializeCredentialDeployment
} from "./serialization";
import BigNumber from "bignumber.js";
import { encodeInt32 } from "./utils";
import { encodeInt32, encodeInt8, encodeWord64 } from "./utils";

const LEDGER_CLA = 0xe0;

Expand Down Expand Up @@ -80,6 +80,7 @@ const INS = {
GET_PUBLIC_KEY: 0x01,
SIGN_TRANSFER: 0x02,
SIGN_TRANSFER_SCHEDULE: 0x03,
SIGN_CREDENTIAL_DEPLOYMENT: 0x04,
SIGN_TRANSFER_TO_PUBLIC: 0x12,
SIGN_CONFIGURE_DELEGATION: 0x17,
SIGN_CONFIGURE_BAKER: 0x18,
Expand Down Expand Up @@ -567,6 +568,109 @@ export default class Concordium {
};
}

async signCredentialDeployment(txn, isNew: boolean, addressOrExpiry: string | BigInt, path: string): Promise<{ signature: string[] }> {

const { payloadDerivationPath, numberOfVerificationKeys, keyIndexAndSchemeAndVerificationKey, thresholdAndRegIdAndIPIdentity, encIdCredPubShareAndKey, validToAndCreatedAtAndAttributesLength, tag, valueLength, value, proofLength, proofs } = serializeCredentialDeployment(txn, path);

let response;
response = await this.sendToDevice(
INS.SIGN_CREDENTIAL_DEPLOYMENT,
P1_INITIAL_PACKET,
NONE,
payloadDerivationPath
);


response = await this.sendToDevice(
INS.SIGN_CREDENTIAL_DEPLOYMENT,
P1_VERIFICATION_KEY_LENGTH,
NONE,
numberOfVerificationKeys
);
response = await this.sendToDevice(
INS.SIGN_CREDENTIAL_DEPLOYMENT,
P1_VERIFICATION_KEY,
NONE,
keyIndexAndSchemeAndVerificationKey
);
response = await this.sendToDevice(
INS.SIGN_CREDENTIAL_DEPLOYMENT,
P1_SIGNATURE_THRESHOLD,
NONE,
thresholdAndRegIdAndIPIdentity
);
response = await this.sendToDevice(
INS.SIGN_CREDENTIAL_DEPLOYMENT,
P1_AR_IDENTITY,
NONE,
encIdCredPubShareAndKey
);
response = await this.sendToDevice(
INS.SIGN_CREDENTIAL_DEPLOYMENT,
P1_CREDENTIAL_DATES,
NONE,
validToAndCreatedAtAndAttributesLength
);
for (let i = 0; i < Object.keys(txn.policy.revealedAttributes).length; i++) {
const tagAndValueLength = Buffer.concat([tag[i], valueLength[i]])
response = await this.sendToDevice(
INS.SIGN_CREDENTIAL_DEPLOYMENT,
P1_ATTRIBUTE_TAG,
NONE,
tagAndValueLength
);
response = await this.sendToDevice(
INS.SIGN_CREDENTIAL_DEPLOYMENT,
P1_ATTRIBUTE_VALUE,
NONE,
value[i]
);
}
response = await this.sendToDevice(
INS.SIGN_CREDENTIAL_DEPLOYMENT,
P1_LENGTH_OF_PROOFS,
NONE,
proofLength
);

const proofPayload = serializeTransactionPayloads(proofs);
for (let i = 0; i < proofPayload.length; i++) {
response = await this.sendToDevice(
INS.SIGN_CREDENTIAL_DEPLOYMENT,
P1_PROOFS,
NONE,
proofPayload[i]
);
}

if (isNew) {
const isNew = encodeInt8(0);
const serializeExpiry = encodeWord64(addressOrExpiry as BigInt);
const expiry = Buffer.concat([isNew, serializeExpiry])
response = await this.sendToDevice(
INS.SIGN_CREDENTIAL_DEPLOYMENT,
P1_NEW_OR_EXISTING,
NONE,
expiry
);
} else {
const isNew = encodeInt8(1);
const address = Buffer.concat([isNew, Buffer.from(addressOrExpiry as string, "hex")])
response = await this.sendToDevice(
INS.SIGN_CREDENTIAL_DEPLOYMENT,
P1_NEW_OR_EXISTING,
NONE,
address
);
}

if (response.length === 1) throw new Error("User has declined.");

return {
signature: response.toString("hex"),
};
}

async signUpdateCredentials(txn, path: string): Promise<{ signature: string[] }> {

const { payloadHeaderKindAndIndexLength, credentialIndex, numberOfVerificationKeys, keyIndexAndSchemeAndVerificationKey, thresholdAndRegIdAndIPIdentity, encIdCredPubShareAndKey, validToAndCreatedAtAndAttributesLength, tag, valueLength, value, proofLength, proofs, credentialIdCount, credentialIds, threshold } = serializeUpdateCredentials(txn, path);
Expand Down
50 changes: 49 additions & 1 deletion src/serialization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { encodeDataBlob, encodeInt8, encodeWord16, encodeWord64, serializeAccoun
import { DataBlob } from "@concordium/common-sdk/lib/types/DataBlob";
import { Buffer as NodeBuffer } from 'buffer/index';
import { AccountAddress } from "@concordium/web-sdk";
import { serializeCredentialDeploymentInfo } from "@concordium/common-sdk/lib/serialization";

const MAX_CHUNK_SIZE = 255;
const MAX_SCHEDULE_CHUNK_SIZE = 15;
Expand Down Expand Up @@ -344,6 +345,53 @@ export const serializeUpdateContract = (txn: any, path: string): { payloads: Buf
return serializeTransaction(txn, path);
};

export const serializeCredentialDeployment = (txn: any, path: string): { payloadDerivationPath: Buffer, numberOfVerificationKeys: Buffer, keyIndexAndSchemeAndVerificationKey: Buffer, thresholdAndRegIdAndIPIdentity: Buffer, encIdCredPubShareAndKey: Buffer, validToAndCreatedAtAndAttributesLength: Buffer, attributesLength: Buffer, tag: Buffer[], valueLength: Buffer[], value: Buffer[], proofLength: Buffer, proofs: Buffer } => {
let offset = 0;
const txSerialized = serializeCredentialDeploymentInfo(txn);
const payloadDerivationPath = pathToBuffer(path);
let numberOfVerificationKeys: Buffer = Buffer.alloc(0);
let keyIndexAndSchemeAndVerificationKey: Buffer = Buffer.alloc(0);
let thresholdAndRegIdAndIPIdentity: Buffer = Buffer.alloc(0);
let encIdCredPubShareAndKey: Buffer = Buffer.alloc(0);
let validToAndCreatedAtAndAttributesLength: Buffer = Buffer.alloc(0);
let attributesLength: Buffer = Buffer.alloc(0);
let tag: Buffer[] = [];
let valueLength: Buffer[] = [];
let value: Buffer[] = [];
let proofLength: Buffer = Buffer.alloc(0);
let proofs: Buffer = Buffer.alloc(0);

numberOfVerificationKeys = Buffer.from(txSerialized.subarray(offset, offset + INDEX_LENGTH));
offset += INDEX_LENGTH;
keyIndexAndSchemeAndVerificationKey = Buffer.from(txSerialized.subarray(offset, offset + 2 * ONE_OCTET_LENGTH + KEY_LENGTH));
offset += 2 * ONE_OCTET_LENGTH + KEY_LENGTH;
thresholdAndRegIdAndIPIdentity = Buffer.from(txSerialized.subarray(offset, offset + 2 * ONE_OCTET_LENGTH + REG_ID_LENGTH + IP_IDENTITY_LENGTH + AR_DATA_LENGTH));
offset += 2 * ONE_OCTET_LENGTH + REG_ID_LENGTH + IP_IDENTITY_LENGTH + AR_DATA_LENGTH;
encIdCredPubShareAndKey = Buffer.from(txSerialized.subarray(offset, offset + 4 * ONE_OCTET_LENGTH + ID_CRED_PUB_SHARE_LENGTH));
offset += 4 * ONE_OCTET_LENGTH + ID_CRED_PUB_SHARE_LENGTH;
validToAndCreatedAtAndAttributesLength = Buffer.from(txSerialized.subarray(offset, offset + ATTRIBUTES_LENGTH + VALID_TO_LENGTH + CREATED_AT_LENGTH));
offset += ATTRIBUTES_LENGTH + VALID_TO_LENGTH + CREATED_AT_LENGTH;
attributesLength = validToAndCreatedAtAndAttributesLength.subarray(-ATTRIBUTES_LENGTH);
tag = [];
valueLength = [];
value = [];
for (let j = 0; j < attributesLength.readUInt16BE(0); j++) {
tag.push(Buffer.from(txSerialized.subarray(offset, offset + TAG_LENGTH)));
offset += TAG_LENGTH;
valueLength.push(Buffer.from(txSerialized.subarray(offset, offset + VALUE_LENGTH)));
offset += VALUE_LENGTH;
value.push(Buffer.from(txSerialized.subarray(offset, offset + valueLength[j].readUInt8(0))));
offset += valueLength[j].readUInt8(0);
}

proofLength = Buffer.from(txSerialized.subarray(offset, offset + PROOF_LENGTH_LENGTH));
offset += PROOF_LENGTH_LENGTH;
proofs = Buffer.from(txSerialized.subarray(offset, offset + proofLength.readUInt32BE(0)));
offset += proofLength.readUInt32BE(0);

return { payloadDerivationPath, numberOfVerificationKeys, keyIndexAndSchemeAndVerificationKey, thresholdAndRegIdAndIPIdentity, encIdCredPubShareAndKey, validToAndCreatedAtAndAttributesLength, attributesLength, tag, valueLength, value, proofLength, proofs };
};

export const serializeUpdateCredentials = (txn: any, path: string): { payloadHeaderKindAndIndexLength: Buffer[], credentialIndex: Buffer[], numberOfVerificationKeys: Buffer[], keyIndexAndSchemeAndVerificationKey: Buffer[], thresholdAndRegIdAndIPIdentity: Buffer[], encIdCredPubShareAndKey: Buffer[], validToAndCreatedAtAndAttributesLength: Buffer[], attributesLength: Buffer[], tag: Buffer[][], valueLength: Buffer[][], value: Buffer[][], proofLength: Buffer[], proofs: Buffer[], credentialIdCount: Buffer, credentialIds: Buffer[], threshold: Buffer } => {
let offset = 0;
const txSerialized = serializeAccountTransaction(txn);
Expand All @@ -358,7 +406,7 @@ export const serializeUpdateCredentials = (txn: any, path: string): { payloadHea
let encIdCredPubShareAndKey: Buffer[] = [];
let validToAndCreatedAtAndAttributesLength: Buffer[] = [];
let attributesLength: Buffer[] = [];
let tag: Buffer[][] = [[]];
let tag: Buffer[][] = [[]];
let valueLength: Buffer[][] = [[]];
let value: Buffer[][] = [[]];
let proofLength: Buffer[] = [];
Expand Down

0 comments on commit 3499e0e

Please sign in to comment.