diff --git a/examples/CHANGELOG.md b/examples/CHANGELOG.md index b960aec2e..6bb704d64 100644 --- a/examples/CHANGELOG.md +++ b/examples/CHANGELOG.md @@ -1,5 +1,14 @@ # @docknetwork/sdk-examples +## 0.22.5 + +### Patch Changes + +- Updated dependencies + - @docknetwork/credential-sdk@0.55.0 + - @docknetwork/cheqd-blockchain-api@5.0.0 + - @docknetwork/cheqd-blockchain-modules@5.0.0 + ## 0.22.4 ### Patch Changes diff --git a/examples/package.json b/examples/package.json index d323eacf2..65c536c71 100644 --- a/examples/package.json +++ b/examples/package.json @@ -2,7 +2,7 @@ "name": "@docknetwork/sdk-examples", "private": true, "type": "module", - "version": "0.22.4", + "version": "0.22.5", "scripts": { "bbs-dock-example": "babel-node ./src/bbs-dock.js", "claim-deduction-example": "babel-node ./src/claim-deduction.js", @@ -18,9 +18,9 @@ "lint": "eslint \"src/**/*.js\"" }, "dependencies": { - "@docknetwork/credential-sdk": "0.54.19", - "@docknetwork/cheqd-blockchain-api": "4.2.2", - "@docknetwork/cheqd-blockchain-modules": "4.0.9" + "@docknetwork/credential-sdk": "0.55.0", + "@docknetwork/cheqd-blockchain-api": "5.0.0", + "@docknetwork/cheqd-blockchain-modules": "5.0.0" }, "devDependencies": { "babel-eslint": "^10.1.0", diff --git a/packages/cheqd-blockchain-api/CHANGELOG.md b/packages/cheqd-blockchain-api/CHANGELOG.md index 804c5f16b..503c5829a 100644 --- a/packages/cheqd-blockchain-api/CHANGELOG.md +++ b/packages/cheqd-blockchain-api/CHANGELOG.md @@ -1,5 +1,12 @@ # @docknetwork/cheqd-blockchain-api +## 5.0.0 + +### Patch Changes + +- Updated dependencies + - @docknetwork/credential-sdk@0.55.0 + ## 4.2.2 ### Patch Changes diff --git a/packages/cheqd-blockchain-api/package.json b/packages/cheqd-blockchain-api/package.json index 63795e9ac..17f7321d6 100644 --- a/packages/cheqd-blockchain-api/package.json +++ b/packages/cheqd-blockchain-api/package.json @@ -1,6 +1,6 @@ { "name": "@docknetwork/cheqd-blockchain-api", - "version": "4.2.2", + "version": "5.0.0", "license": "MIT", "main": "./dist/esm/index.js", "type": "module", @@ -32,7 +32,7 @@ "node": ">=22.0.0" }, "peerDependencies": { - "@docknetwork/credential-sdk": "^0.54.19" + "@docknetwork/credential-sdk": "^0.55.0" }, "dependencies": { "@cheqd/sdk": "5.5.0", @@ -46,7 +46,7 @@ "@babel/plugin-transform-modules-commonjs": "^7.24.1", "@babel/preset-env": "^7.24.3", "@comunica/types": "^1.0.0", - "@docknetwork/credential-sdk": "^0.54.19", + "@docknetwork/credential-sdk": "^0.55.0", "@helia/strings": "^3.0.1", "@rollup/plugin-alias": "^4.0.2", "@rollup/plugin-commonjs": "^24.0.0", diff --git a/packages/cheqd-blockchain-modules/CHANGELOG.md b/packages/cheqd-blockchain-modules/CHANGELOG.md index e4090838d..4065dc07f 100644 --- a/packages/cheqd-blockchain-modules/CHANGELOG.md +++ b/packages/cheqd-blockchain-modules/CHANGELOG.md @@ -1,5 +1,12 @@ # @docknetwork/cheqd-blockchain-modules +## 5.0.0 + +### Patch Changes + +- Updated dependencies + - @docknetwork/credential-sdk@0.55.0 + ## 4.0.9 ### Patch Changes diff --git a/packages/cheqd-blockchain-modules/package.json b/packages/cheqd-blockchain-modules/package.json index 7cfd1c66c..53c3faff2 100644 --- a/packages/cheqd-blockchain-modules/package.json +++ b/packages/cheqd-blockchain-modules/package.json @@ -1,6 +1,6 @@ { "name": "@docknetwork/cheqd-blockchain-modules", - "version": "4.0.9", + "version": "5.0.0", "type": "module", "license": "MIT", "main": "./dist/esm/index.js", @@ -32,7 +32,7 @@ "node": ">=22.0.0" }, "peerDependencies": { - "@docknetwork/credential-sdk": "^0.54.19" + "@docknetwork/credential-sdk": "^0.55.0" }, "devDependencies": { "@babel/cli": "^7.24.1", @@ -41,8 +41,8 @@ "@babel/plugin-syntax-import-attributes": "^7.25.6", "@babel/plugin-transform-modules-commonjs": "^7.24.1", "@babel/preset-env": "^7.24.3", - "@docknetwork/cheqd-blockchain-api": "4.2.2", - "@docknetwork/credential-sdk": "^0.54.19", + "@docknetwork/cheqd-blockchain-api": "5.0.0", + "@docknetwork/credential-sdk": "^0.55.0", "@rollup/plugin-alias": "^4.0.2", "@rollup/plugin-babel": "^6.0.4", "@rollup/plugin-commonjs": "^24.0.0", diff --git a/packages/credential-sdk/CHANGELOG.md b/packages/credential-sdk/CHANGELOG.md index aef23dd6c..4fedd68d8 100644 --- a/packages/credential-sdk/CHANGELOG.md +++ b/packages/credential-sdk/CHANGELOG.md @@ -1,5 +1,11 @@ # @docknetwork/credential-sdk +## 0.55.0 + +### Minor Changes + +- secp256r1 key support + ## 0.54.19 ### Patch Changes diff --git a/packages/credential-sdk/package.json b/packages/credential-sdk/package.json index 617ad9845..bcd0c02b8 100644 --- a/packages/credential-sdk/package.json +++ b/packages/credential-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@docknetwork/credential-sdk", - "version": "0.54.19", + "version": "0.55.0", "license": "MIT", "type": "module", "files": [ diff --git a/packages/credential-sdk/src/keypairs/index.js b/packages/credential-sdk/src/keypairs/index.js index 0538800fa..bc57c7ecd 100644 --- a/packages/credential-sdk/src/keypairs/index.js +++ b/packages/credential-sdk/src/keypairs/index.js @@ -1,4 +1,5 @@ export { default as DockKeypair } from './dock-keypair'; export { default as Ed25519Keypair } from './keypair-ed25519'; export { default as Secp256k1Keypair } from './keypair-secp256k1'; +export { default as Secp256r1Keypair } from './keypair-secp256r1'; export { default as DidKeypair } from './did-keypair'; diff --git a/packages/credential-sdk/src/keypairs/keypair-secp256r1.js b/packages/credential-sdk/src/keypairs/keypair-secp256r1.js new file mode 100644 index 000000000..497404d24 --- /dev/null +++ b/packages/credential-sdk/src/keypairs/keypair-secp256r1.js @@ -0,0 +1,123 @@ +import elliptic from 'elliptic'; +import { sha256 } from 'js-sha256'; + +import { SignatureSecp256r1 } from '../types/signatures'; +import { EcdsaSecp256r1VerKeyName } from '../vc/crypto/constants'; +import DockKeypair from './dock-keypair'; +import { hexToU8a, normalizeToU8a, valueBytes } from '../utils'; + +const EC = elliptic.ec; +const secp256r1Curve = new EC('p256'); + +function encodeDERInt(intBytes) { + let i = 0; + while (i < intBytes.length && intBytes[i] === 0) { + i++; + } + + let trimmedBytes = intBytes.slice(i); + + // eslint-disable-next-line no-bitwise + if (trimmedBytes[0] & 0x80) { + trimmedBytes = Uint8Array.of(0, ...trimmedBytes); + } + + const { length } = trimmedBytes; + return [0x02, length, ...trimmedBytes]; +} + +export default class Secp256r1Keypair extends DockKeypair { + static Signature = SignatureSecp256r1; + + static VerKeyType = EcdsaSecp256r1VerKeyName; + + static SeedSize = 32; + + constructor(entropyOrPrivate, sourceType = 'entropy') { + let kp; + switch (sourceType) { + case 'entropy': + if (entropyOrPrivate == null) { + throw new Error('Entropy must be provided'); + } + + kp = secp256r1Curve.genKeyPair({ + entropy: entropyOrPrivate, + }); + break; + case 'private': + kp = secp256r1Curve.keyFromPrivate(normalizeToU8a(entropyOrPrivate)); + break; + default: + throw new Error( + `Unknown source type: \`${sourceType}\`, it must be either "entropy" or "private"`, + ); + } + + super(kp); + } + + _publicKey() { + return hexToU8a(`0x${this.keyPair.getPublic(true, 'hex')}`); + } + + privateKey() { + return hexToU8a(`0x${this.keyPair.getPrivate('hex')}`); + } + + _sign(message) { + const hash = this.constructor.hash(message); + const sig = this.keyPair.sign(hash, { + canonical: true, + }); + + const r = sig.r.toString('hex', 32); + const s = sig.s.toString('hex', 32); + const i = sig.recoveryParam.toString(16).padStart(2, '0'); + + return hexToU8a(`0x${r}${s}${i}`); + } + + static signatureToDER(signature) { + const sigBytes = valueBytes(signature); + if (sigBytes.length !== 65) { + throw new Error( + `Invalid signature length. Expected is 65 bytes, received ${sigBytes.length}`, + ); + } + + const r = sigBytes.slice(0, 32); + const s = sigBytes.slice(32, 64); + + const rEncoded = encodeDERInt(r); + const sEncoded = encodeDERInt(s); + + const totalLength = rEncoded.length + sEncoded.length; + + const der = new Uint8Array(2 + totalLength); + der[0] = 0x30; + der[1] = totalLength; + + der.set(rEncoded, 2); + der.set(sEncoded, 2 + rEncoded.length); + + return der; + } + + static hash(message) { + return sha256.digest(message); + } + + static verify(message, signature, publicKey) { + let bytes = valueBytes(signature); + if (bytes.length === 65) { + bytes = this.signatureToDER(bytes); + } + + return secp256r1Curve.verify( + this.hash(message), + bytes, + valueBytes(publicKey), + ); + } +} diff --git a/packages/credential-sdk/src/types/did/document/verification-method-type.js b/packages/credential-sdk/src/types/did/document/verification-method-type.js index 73078b8e8..ae7cb32f5 100644 --- a/packages/credential-sdk/src/types/did/document/verification-method-type.js +++ b/packages/credential-sdk/src/types/did/document/verification-method-type.js @@ -1,6 +1,7 @@ import { TypedEnum, Null } from '../../generic'; import { EcdsaSecp256k1VerKeyName, + EcdsaSecp256r1VerKeyName, Ed255192020VerKeyName, Ed25519VerKeyName, Sr25519VerKeyName, @@ -37,6 +38,11 @@ export class EcdsaSecp256k1VerificationKey2019 extends VerificationMethodType { static Type = EcdsaSecp256k1VerKeyName; } +export class EcdsaSecp256r1VerificationKey2019 extends VerificationMethodType { + static Class = Null; + + static Type = EcdsaSecp256r1VerKeyName; +} export class X25519KeyAgreementKey2019 extends VerificationMethodType { static Class = Null; @@ -67,6 +73,7 @@ VerificationMethodType.bindVariants( Ed25519Verification2020Method, Sr25519Verification2020Method, EcdsaSecp256k1VerificationKey2019, + EcdsaSecp256r1VerificationKey2019, X25519KeyAgreementKey2019, Bls12381G2VerificationKeyDock2022, Bls12381BBSVerificationKeyDock2023, diff --git a/packages/credential-sdk/src/types/did/document/verification-method.js b/packages/credential-sdk/src/types/did/document/verification-method.js index f15831b30..da8671242 100644 --- a/packages/credential-sdk/src/types/did/document/verification-method.js +++ b/packages/credential-sdk/src/types/did/document/verification-method.js @@ -27,10 +27,12 @@ import { import { PublicKeyEd25519, PublicKeySecp256k1, + PublicKeySecp256r1, PublicKeySr25519, } from '../../public-keys'; import { EcdsaSecp256k1VerKeyName, + EcdsaSecp256r1VerKeyName, Ed255192020VerKeyName, Ed25519VerKeyName, Sr25519VerKeyName, @@ -233,6 +235,8 @@ export class VerificationMethod extends withFrom( return PublicKeyEd25519; case EcdsaSecp256k1VerKeyName: return PublicKeySecp256k1; + case EcdsaSecp256r1VerKeyName: + return PublicKeySecp256r1; case Bls12381BBSDockVerKeyName: return BBSPlusPublicKey; case Bls12381BBS23DockVerKeyName: diff --git a/packages/credential-sdk/src/types/did/onchain/constants.js b/packages/credential-sdk/src/types/did/onchain/constants.js index bd4afc2d3..85c7d0905 100644 --- a/packages/credential-sdk/src/types/did/onchain/constants.js +++ b/packages/credential-sdk/src/types/did/onchain/constants.js @@ -1,6 +1,7 @@ export const DockDIDMethod = 'dock'; export const CheqdDIDMethod = 'cheqd'; export const Secp256k1PublicKeyPrefix = 'zQ3s'; +export const Secp256r1PublicKeyPrefix = 'zDn'; export const Ed25519PublicKeyPrefix = 'z6Mk'; export const BBS23PublicKeyPrefix = 'zVMC'; export const BBSPlusPublicKeyPrefix = 'zVTu'; @@ -15,16 +16,19 @@ export const CheqdDIDByteSize = 16; export const DidMethodKeyQualifier = 'did:key:'; export const DidMethodKeySecp256k1ByteSize = 33; +export const DidMethodKeySecp256r1ByteSize = 33; export const DidMethodKeyEd25519ByteSize = 32; export const DidMethodKeyBBS23ByteSize = 96; export const DidMethodKeyBBSPlusByteSize = 96; export const DidMethodKeySecp256k1Prefix = `${DidMethodKeyQualifier}${Secp256k1PublicKeyPrefix}`; +export const DidMethodKeySecp256r1Prefix = `${DidMethodKeyQualifier}${Secp256r1PublicKeyPrefix}`; export const DidMethodKeyEd25519Prefix = `${DidMethodKeyQualifier}${Ed25519PublicKeyPrefix}`; export const DidMethodKeyBBS23Prefix = `${DidMethodKeyQualifier}${BBS23PublicKeyPrefix}`; export const DidMethodKeyBBSPlusPrefix = `${DidMethodKeyQualifier}${BBSPlusPublicKeyPrefix}`; export const DidMethodKeyBytePrefixEd25519 = new Uint8Array([0xed, 0x01]); export const DidMethodKeyBytePrefixSecp256k1 = new Uint8Array([0xe7, 0x01]); +export const DidMethodKeyBytePrefixSecp256r1 = new Uint8Array([0x80, 0x24]); export const DidMethodKeyBytePrefixBBS23 = new Uint8Array([0xf5, 0x01]); export const DidMethodKeyBytePrefixBBSPlus = new Uint8Array([0xf6, 0x01]); diff --git a/packages/credential-sdk/src/types/did/onchain/did-key.js b/packages/credential-sdk/src/types/did/onchain/did-key.js index be20abe75..e25893a86 100644 --- a/packages/credential-sdk/src/types/did/onchain/did-key.js +++ b/packages/credential-sdk/src/types/did/onchain/did-key.js @@ -4,6 +4,7 @@ import { import { PublicKeyEd25519Value, PublicKeySecp256k1Value, + PublicKeySecp256r1Value, PublicKeySr25519Value, PublicKeyX25519Value, } from '../../public-keys'; @@ -51,6 +52,11 @@ export class DidKeySecp256k1PublicKey extends DidKeyValue { static Class = PublicKeySecp256k1Value; } +export class DidKeySecp256r1PublicKey extends DidKeyValue { + static Type = 'secp256r1'; + + static Class = PublicKeySecp256r1Value; +} /** * Class representing Sr25519 PublicKey * @class @@ -96,6 +102,7 @@ export class DidKeyPSPublicKey extends DidKeyValue { DidKeyValue.bindVariants( DidKeyEd25519PublicKey, DidKeySecp256k1PublicKey, + DidKeySecp256r1PublicKey, DidKeySr25519PublicKey, DidKeyX25519PublicKey, DidKeyBBSPublicKey, @@ -107,6 +114,7 @@ const Signing = [ DidKeyEd25519PublicKey, DidKeySr25519PublicKey, DidKeySecp256k1PublicKey, + DidKeySecp256r1PublicKey, ]; const Assertion = [ diff --git a/packages/credential-sdk/src/types/did/onchain/typed-did/did-method-key/did-method-key-public-key.js b/packages/credential-sdk/src/types/did/onchain/typed-did/did-method-key/did-method-key-public-key.js index 430533aec..6f46ad482 100644 --- a/packages/credential-sdk/src/types/did/onchain/typed-did/did-method-key/did-method-key-public-key.js +++ b/packages/credential-sdk/src/types/did/onchain/typed-did/did-method-key/did-method-key-public-key.js @@ -10,6 +10,7 @@ import { import { PublicKeyEd25519Value, PublicKeySecp256k1Value, + PublicKeySecp256r1Value, } from '../../../../public-keys'; import { DidMethodKeyBBS23ByteSize, @@ -18,6 +19,7 @@ import { DidMethodKeyBytePrefixBBSPlus, DidMethodKeyBytePrefixEd25519, DidMethodKeyBytePrefixSecp256k1, + DidMethodKeyBytePrefixSecp256r1, DidMethodKeyQualifier, } from '../../constants'; import DidOrDidMethodKeySignature from '../signature'; @@ -54,6 +56,9 @@ export class DidMethodKeyPublicKey extends withQualifier(TypedEnum) { if (hasPrefix(DidMethodKeyBytePrefixSecp256k1)) { // eslint-disable-next-line no-use-before-define PublicKey = DidMethodKeyPublicKeySecp256k1; + } else if (hasPrefix(DidMethodKeyBytePrefixSecp256r1)) { + // eslint-disable-next-line no-use-before-define + PublicKey = DidMethodKeyPublicKeySecp256r1; } else if (hasPrefix(DidMethodKeyBytePrefixEd25519)) { // eslint-disable-next-line no-use-before-define PublicKey = DidMethodKeyPublicKeyEd25519; @@ -142,6 +147,14 @@ export class DidMethodKeyPublicKeySecp256k1 extends DidMethodKeyPublicKey { static Prefix = DidMethodKeyBytePrefixSecp256k1; } +export class DidMethodKeyPublicKeySecp256r1 extends DidMethodKeyPublicKey { + static Class = PublicKeySecp256r1Value; + + static Type = PublicKeySecp256r1Value.Type; + + static Prefix = DidMethodKeyBytePrefixSecp256r1; +} + class PublicKeyBBSValue extends sized(TypedBytes) { static Type = 'bbs'; @@ -177,6 +190,7 @@ export class DidMethodKeyPublicKeyBBSPlus extends DidMethodKeyPublicKey { DidMethodKeyPublicKey.bindVariants( DidMethodKeyPublicKeyEd25519, DidMethodKeyPublicKeySecp256k1, + DidMethodKeyPublicKeySecp256r1, DidMethodKeyPublicKeyBBS, DidMethodKeyPublicKeyBBSPlus, ); diff --git a/packages/credential-sdk/src/types/did/onchain/typed-did/did-method-key/did-method-key-signature.js b/packages/credential-sdk/src/types/did/onchain/typed-did/did-method-key/did-method-key-signature.js index 8d8d85fbb..9b718f247 100644 --- a/packages/credential-sdk/src/types/did/onchain/typed-did/did-method-key/did-method-key-signature.js +++ b/packages/credential-sdk/src/types/did/onchain/typed-did/did-method-key/did-method-key-signature.js @@ -2,6 +2,7 @@ import { TypedEnum } from '../../../../generic'; import { SignatureEd25519Value, SignatureSecp256k1Value, + SignatureSecp256r1Value, } from '../../../../signatures'; export class DidMethodKeySignatureValue extends TypedEnum {} @@ -11,8 +12,12 @@ export class DidMethodKeySignatureValueEd25519 extends DidMethodKeySignatureValu export class DidMethodKeySignatureValueSecp256k1 extends DidMethodKeySignatureValue { static Class = SignatureSecp256k1Value; } +export class DidMethodKeySignatureValueSecp256r1 extends DidMethodKeySignatureValue { + static Class = SignatureSecp256r1Value; +} DidMethodKeySignatureValue.bindVariants( DidMethodKeySignatureValueEd25519, DidMethodKeySignatureValueSecp256k1, + DidMethodKeySignatureValueSecp256r1, ); diff --git a/packages/credential-sdk/src/types/public-keys/index.js b/packages/credential-sdk/src/types/public-keys/index.js index 21ab418ea..6b85914d4 100644 --- a/packages/credential-sdk/src/types/public-keys/index.js +++ b/packages/credential-sdk/src/types/public-keys/index.js @@ -3,4 +3,5 @@ export * from './public-key'; export { default as PublicKeySr25519Value } from './public-key-sr25519-value'; export { default as PublicKeyEd25519Value } from './public-key-ed25519-value'; export { default as PublicKeySecp256k1Value } from './public-key-secp256k1-value'; +export { default as PublicKeySecp256r1Value } from './public-key-secp256r1-value'; export { default as PublicKeyX25519Value } from './public-key-x25519-value'; diff --git a/packages/credential-sdk/src/types/public-keys/public-key-secp256r1-value.js b/packages/credential-sdk/src/types/public-keys/public-key-secp256r1-value.js new file mode 100644 index 000000000..d19a1e3ec --- /dev/null +++ b/packages/credential-sdk/src/types/public-keys/public-key-secp256r1-value.js @@ -0,0 +1,11 @@ +import { sized, TypedBytes } from '../generic'; +import { EcdsaSecp256r1VerKeyName } from '../../vc/crypto/constants'; + +/** Class representing value of a compressed Secp256r1 PublicKey */ +export default class PublicKeySecp256r1Value extends sized(TypedBytes) { + static Type = 'secp256r1'; + + static Size = 33; + + static VerKeyType = EcdsaSecp256r1VerKeyName; +} diff --git a/packages/credential-sdk/src/types/public-keys/public-key.js b/packages/credential-sdk/src/types/public-keys/public-key.js index 7ab0c74d7..25eeb1227 100644 --- a/packages/credential-sdk/src/types/public-keys/public-key.js +++ b/packages/credential-sdk/src/types/public-keys/public-key.js @@ -2,6 +2,7 @@ import { TypedEnum } from '../generic'; import PublicKeyX25519Value from './public-key-x25519-value'; import PublicKeyEd25519Value from './public-key-ed25519-value'; import PublicKeySecp256k1Value from './public-key-secp256k1-value'; +import PublicKeySecp256r1Value from './public-key-secp256r1-value'; import PublicKeySr25519Value from './public-key-sr25519-value'; /** @@ -30,6 +31,14 @@ export class PublicKeyEd25519 extends PublicKey { export class PublicKeySecp256k1 extends PublicKey { static Class = PublicKeySecp256k1Value; } +/** + * Class representing Secp256r1 PublicKey + * @class + * @extends {PublicKey} + */ +export class PublicKeySecp256r1 extends PublicKey { + static Class = PublicKeySecp256r1Value; +} /** * Class representing Sr25519 PublicKey * @class @@ -50,6 +59,7 @@ export class PublicKeyX25519 extends PublicKey { PublicKey.bindVariants( PublicKeyEd25519, PublicKeySecp256k1, + PublicKeySecp256r1, PublicKeySr25519, PublicKeyX25519, ); diff --git a/packages/credential-sdk/src/types/signatures/index.js b/packages/credential-sdk/src/types/signatures/index.js index c4bc4952a..e67215aea 100644 --- a/packages/credential-sdk/src/types/signatures/index.js +++ b/packages/credential-sdk/src/types/signatures/index.js @@ -1,10 +1,12 @@ import SignatureSr25519Value from './signature-sr25519-value'; import SignatureEd25519Value from './signature-ed25519-value'; import SignatureSecp256k1Value from './signature-secp256k1-value'; +import SignatureSecp256r1Value from './signature-secp256r1-value'; export { SignatureSr25519Value, SignatureEd25519Value, SignatureSecp256k1Value, + SignatureSecp256r1Value, }; export * from './signature'; diff --git a/packages/credential-sdk/src/types/signatures/signature-secp256r1-value.js b/packages/credential-sdk/src/types/signatures/signature-secp256r1-value.js new file mode 100644 index 000000000..7a84a6d07 --- /dev/null +++ b/packages/credential-sdk/src/types/signatures/signature-secp256r1-value.js @@ -0,0 +1,9 @@ +import SignatureValue from './signature-value'; +import { PublicKeySecp256r1 } from '../public-keys'; + +/** Class representing a Secp256r1 Signature */ +export default class SignatureSecp256r1Value extends SignatureValue { + static PublicKey = PublicKeySecp256r1; + + static Size = 65; +} diff --git a/packages/credential-sdk/src/types/signatures/signature.js b/packages/credential-sdk/src/types/signatures/signature.js index 37ce2da80..56e1f6f50 100644 --- a/packages/credential-sdk/src/types/signatures/signature.js +++ b/packages/credential-sdk/src/types/signatures/signature.js @@ -1,6 +1,7 @@ import { TypedEnum } from '../generic'; import SignatureEd25519Value from './signature-ed25519-value'; import SignatureSecp256k1Value from './signature-secp256k1-value'; +import SignatureSecp256r1Value from './signature-secp256r1-value'; import SignatureSr25519Value from './signature-sr25519-value'; /** @@ -33,6 +34,14 @@ export class SignatureEd25519 extends Signature { export class SignatureSecp256k1 extends Signature { static Class = SignatureSecp256k1Value; } +/** + * Class representing Secp256r1 Signature + * @class + * @extends {Signature} + */ +export class SignatureSecp256r1 extends Signature { + static Class = SignatureSecp256r1Value; +} /** * Class representing Sr25519 Signature * @class @@ -42,4 +51,9 @@ export class SignatureSr25519 extends Signature { static Class = SignatureSr25519Value; } -Signature.bindVariants(SignatureEd25519, SignatureSecp256k1, SignatureSr25519); +Signature.bindVariants( + SignatureEd25519, + SignatureSecp256k1, + SignatureSecp256r1, + SignatureSr25519, +); diff --git a/packages/credential-sdk/src/vc/contexts/did-v1-updated.json b/packages/credential-sdk/src/vc/contexts/did-v1-updated.json index 263ecb0e7..412e30d06 100644 --- a/packages/credential-sdk/src/vc/contexts/did-v1-updated.json +++ b/packages/credential-sdk/src/vc/contexts/did-v1-updated.json @@ -10,6 +10,8 @@ "xsd": "http://www.w3.org/2001/XMLSchema#", "EcdsaSecp256k1Signature2019": "sec:EcdsaSecp256k1Signature2019", "EcdsaSecp256k1VerificationKey2019": "sec:EcdsaSecp256k1VerificationKey2019", + "EcdsaSecp256r1Signature2019": "sec:EcdsaSecp256r1Signature2019", + "EcdsaSecp256r1VerificationKey2019": "sec:EcdsaSecp256r1VerificationKey2019", "Ed25519Signature2018": "sec:Ed25519Signature2018", "Ed25519VerificationKey2018": "sec:Ed25519VerificationKey2018", "Sr25519Signature2020": "sec:Sr25519Signature2020", diff --git a/packages/credential-sdk/src/vc/credentials.js b/packages/credential-sdk/src/vc/credentials.js index ceb32918b..cd4ffff8b 100644 --- a/packages/credential-sdk/src/vc/credentials.js +++ b/packages/credential-sdk/src/vc/credentials.js @@ -39,6 +39,7 @@ import { ensureValidDatetime } from '../utils'; import { EcdsaSecp256k1Signature2019, + EcdsaSecp256r1Signature2019, Ed25519Signature2018, Ed25519Signature2020, // Sr25519Signature2020, @@ -379,6 +380,7 @@ export async function verifyCredential( new Ed25519Signature2018(), new Ed25519Signature2020(), new EcdsaSecp256k1Signature2019(), + new EcdsaSecp256r1Signature2019(), // new Sr25519Signature2020(), new JsonWebSignature2020(), new Bls12381BBSSignatureDock2022(anoncredsParams), @@ -616,6 +618,7 @@ export async function verifyPrivateStatus( const fullSuite = [ new Ed25519Signature2018(), new EcdsaSecp256k1Signature2019(), + new EcdsaSecp256r1Signature2019(), // new Sr25519Signature2020(), new JsonWebSignature2020(), ...suite, diff --git a/packages/credential-sdk/src/vc/crypto/EcdsaSecp256r1Signature2019.js b/packages/credential-sdk/src/vc/crypto/EcdsaSecp256r1Signature2019.js new file mode 100644 index 000000000..630596537 --- /dev/null +++ b/packages/credential-sdk/src/vc/crypto/EcdsaSecp256r1Signature2019.js @@ -0,0 +1,39 @@ +import { EcdsaSecp256r1SigName, EcdsaSecp256r1VerKeyName } from './constants'; +import EcdsaSecp256r1VerificationKey2019 from './EcdsaSecp256r1VerificationKey2019'; +import CustomLinkedDataSignature from './common/CustomLinkedDataSignature'; + +const SUITE_CONTEXT_URL = 'https://www.w3.org/2018/credentials/v1'; + +export default class EcdsaSecp256r1Signature2019 extends CustomLinkedDataSignature { + constructor({ + keypair, + verificationMethod, + verifier, + signer, + useProofValue, + } = {}) { + super({ + type: EcdsaSecp256r1SigName, + LDKeyClass: EcdsaSecp256r1VerificationKey2019, + contextUrl: SUITE_CONTEXT_URL, + alg: 'ES256', + signer: + signer + || EcdsaSecp256r1Signature2019.signerFactory(keypair, verificationMethod), + verifier, + useProofValue, + }); + this.requiredKeyType = EcdsaSecp256r1VerKeyName; + } + + static signerFactory(keypair, verificationMethod) { + return { + id: verificationMethod, + async sign({ data }) { + return new Uint8Array( + keypair.keyPair.sign(keypair.constructor.hash(data)).toDER(), + ); + }, + }; + } +} diff --git a/packages/credential-sdk/src/vc/crypto/EcdsaSecp256r1VerificationKey2019.js b/packages/credential-sdk/src/vc/crypto/EcdsaSecp256r1VerificationKey2019.js new file mode 100644 index 000000000..a0e3f3edc --- /dev/null +++ b/packages/credential-sdk/src/vc/crypto/EcdsaSecp256r1VerificationKey2019.js @@ -0,0 +1,58 @@ +import b58 from 'bs58'; +import * as base64 from '@juanelas/base64'; +import { u8aToU8a } from '../../utils/types/bytes'; +import { EcdsaSecp256r1VerKeyName } from './constants'; +import Secp256r1Keypair from '../../keypairs/keypair-secp256r1'; +import { decodeFromMultibase } from '../../utils/encoding/multibase'; + +export default class EcdsaSecp256r1VerificationKey2019 { + constructor(publicKey) { + this.publicKey = u8aToU8a(publicKey); + } + + static from(verificationMethod) { + if ( + !verificationMethod.type + || verificationMethod.type.indexOf(EcdsaSecp256r1VerKeyName) === -1 + ) { + throw new Error( + `verification method should have type ${EcdsaSecp256r1VerKeyName} - got: ${verificationMethod.type}`, + ); + } + + if (verificationMethod.publicKeyBase58) { + return new this(b58.decode(verificationMethod.publicKeyBase58)); + } + + if (verificationMethod.publicKeyBase64) { + return new this(base64.decode(verificationMethod.publicKeyBase64)); + } + + const secMultibase = verificationMethod['sec:publicKeyMultibase']; + const multiBase = verificationMethod.publicKeyMultibase || ( + typeof secMultibase === 'object' + ? secMultibase['@value'] + : secMultibase + ); + + if (multiBase) { + return new this(decodeFromMultibase(multiBase).slice(2)); + } + + throw new Error( + `Unsupported signature encoding for ${EcdsaSecp256r1VerKeyName}`, + ); + } + + verifier() { + return EcdsaSecp256r1VerificationKey2019.verifierFactory(this.publicKey); + } + + static verifierFactory(publicKey) { + return { + async verify({ data, signature }) { + return Secp256r1Keypair.verify(data, signature, publicKey); + }, + }; + } +} diff --git a/packages/credential-sdk/src/vc/crypto/constants.js b/packages/credential-sdk/src/vc/crypto/constants.js index 9514df12a..426d8d494 100644 --- a/packages/credential-sdk/src/vc/crypto/constants.js +++ b/packages/credential-sdk/src/vc/crypto/constants.js @@ -1,5 +1,7 @@ export const EcdsaSecp256k1VerKeyName = 'EcdsaSecp256k1VerificationKey2019'; export const EcdsaSecp256k1SigName = 'EcdsaSecp256k1Signature2019'; +export const EcdsaSecp256r1VerKeyName = 'EcdsaSecp256r1VerificationKey2019'; +export const EcdsaSecp256r1SigName = 'EcdsaSecp256r1Signature2019'; export const Ed25519VerKeyName = 'Ed25519VerificationKey2018'; export const Ed255192020VerKeyName = 'Ed25519VerificationKey2020'; export const Ed25519SigName = 'Ed25519Signature2018'; diff --git a/packages/credential-sdk/src/vc/crypto/index.js b/packages/credential-sdk/src/vc/crypto/index.js index c8fe5f08a..68659ef0c 100644 --- a/packages/credential-sdk/src/vc/crypto/index.js +++ b/packages/credential-sdk/src/vc/crypto/index.js @@ -15,6 +15,8 @@ export { default as Bls12381PSSignatureDock2023 } from './Bls12381PSSignatureDoc export { default as Bls12381PSSignatureProofDock2023 } from './Bls12381PSSignatureProofDock2023'; export { default as EcdsaSecp256k1Signature2019 } from './EcdsaSecp256k1Signature2019'; export { default as EcdsaSecp256k1VerificationKey2019 } from './EcdsaSecp256k1VerificationKey2019'; +export { default as EcdsaSecp256r1Signature2019 } from './EcdsaSecp256r1Signature2019'; +export { default as EcdsaSecp256r1VerificationKey2019 } from './EcdsaSecp256r1VerificationKey2019'; export { default as Ed25519Signature2018 } from './Ed25519Signature2018'; export { default as Ed25519Signature2020 } from './Ed25519Signature2020'; export { default as Ed25519VerificationKey2018 } from './Ed25519VerificationKey2018'; diff --git a/packages/credential-sdk/src/vc/helpers.js b/packages/credential-sdk/src/vc/helpers.js index 166fefe8e..19ef9ee43 100644 --- a/packages/credential-sdk/src/vc/helpers.js +++ b/packages/credential-sdk/src/vc/helpers.js @@ -4,8 +4,10 @@ import defaultDocumentLoader from './document-loader'; import { EcdsaSecp256k1VerKeyName, + EcdsaSecp256r1VerKeyName, Ed25519VerKeyName, EcdsaSecp256k1Signature2019, + EcdsaSecp256r1Signature2019, Ed25519Signature2018, // Sr25519Signature2020, Bls12381BBSSignatureDock2022, @@ -72,6 +74,9 @@ export async function getSuiteFromKeyDoc(keyDoc, useProofValue, options) { case EcdsaSecp256k1VerKeyName: Cls = EcdsaSecp256k1Signature2019; break; + case EcdsaSecp256r1VerKeyName: + Cls = EcdsaSecp256r1Signature2019; + break; case Ed25519VerKeyName: Cls = Ed25519Signature2018; break; diff --git a/packages/credential-sdk/src/vc/presentations.js b/packages/credential-sdk/src/vc/presentations.js index aee4aba83..8c7b67a4a 100644 --- a/packages/credential-sdk/src/vc/presentations.js +++ b/packages/credential-sdk/src/vc/presentations.js @@ -30,6 +30,7 @@ import { DEFAULT_CONTEXT_V1_URL } from './constants'; import { EcdsaSecp256k1Signature2019, + EcdsaSecp256r1Signature2019, Ed25519Signature2018, Ed25519Signature2020, // Sr25519Signature2020, @@ -295,6 +296,7 @@ export async function verifyPresentation(presentation, options = {}) { new Ed25519Signature2018(), new Ed25519Signature2020(), new EcdsaSecp256k1Signature2019(), + new EcdsaSecp256r1Signature2019(), // new Sr25519Signature2020(), new JsonWebSignature2020(), ...suite, diff --git a/packages/credential-sdk/tests/__snapshots__/did.test.js.snap b/packages/credential-sdk/tests/__snapshots__/did.test.js.snap index 0071a7cbe..21e595006 100644 --- a/packages/credential-sdk/tests/__snapshots__/did.test.js.snap +++ b/packages/credential-sdk/tests/__snapshots__/did.test.js.snap @@ -2,4 +2,6 @@ exports[`\`DockDidOrDidMethodKey.from\` \`DidMethodKey.from\` work for a raw did:key 1`] = `"Unsupported qualified string: \`zQ3shokFTS3brHcDQrn82RUDfCZESWL1ZdCEJwekUDPQiYBme\`, expected with either prefix: [did:dock:, did:key:]"`; +exports[`\`DockDidOrDidMethodKey.from\` \`DidMethodKey.from\` work for a raw did:key secp256r1 1`] = `"Unsupported qualified string: \`zDnaermRkDvx3hSXzEqmFuuSz3HHEuNwj71huxaJ7UsKWhUy2\`, expected with either prefix: [did:dock:, did:key:]"`; + exports[`\`DockDidOrDidMethodKey.from\` \`DockDid.from\` work for a raw did 1`] = `"Unsupported qualified string: \`5DEHasvC9G3eVF3qCsN2VQvEbHYdQtsv74ozZ1ngQQj39Luk\`, expected with either prefix: [did:dock:, did:key:]"`; diff --git a/packages/credential-sdk/tests/claim-deduction.test.js b/packages/credential-sdk/tests/claim-deduction.test.js index d4a157209..fa45fe686 100644 --- a/packages/credential-sdk/tests/claim-deduction.test.js +++ b/packages/credential-sdk/tests/claim-deduction.test.js @@ -23,12 +23,19 @@ import { modifyDocument, } from './utils/cached-document-loader'; -import { Secp256k1Keypair } from '../src/keypairs'; +import { Secp256k1Keypair, Secp256r1Keypair } from '../src/keypairs'; import { newDid } from './utils/did-helpers'; -describe('Composite claim soundness checker', () => { +let activeKeypairClass = Secp256k1Keypair; + +describe.each([Secp256k1Keypair, Secp256r1Keypair])( + 'Composite claim soundness checker (%s)', + (KeypairClass) => { + beforeAll(() => { + activeKeypairClass = KeypairClass; + }); test('control: issue and verify', async () => { - const { did: issuer, suite: kp } = await newDid(); + const { did: issuer, suite: kp } = await newDid(activeKeypairClass); const cred = { '@context': [ @@ -53,8 +60,8 @@ describe('Composite claim soundness checker', () => { }); test('assumption: credential with false issuer will fail', async () => { - const { did: issuera, suite: kpa } = await newDid(); - const { did: issuerb, suite: kpb } = await newDid(); + const { did: issuera, suite: kpa } = await newDid(activeKeypairClass); + const { did: issuerb, suite: kpb } = await newDid(activeKeypairClass); // fyi signing a cred does modify the cred by adding a proof const cred = () => ({ @@ -233,8 +240,8 @@ describe('Composite claim soundness checker', () => { }); test('bddap is named Gorgadon because joe is a pig that can fly', async () => { - const { did: pigchecker, suite: pigchecker_kp } = await newDid(); - const { did: faa, suite: faa_kp } = await newDid(); + const { did: pigchecker, suite: pigchecker_kp } = await newDid(activeKeypairClass); + const { did: faa, suite: faa_kp } = await newDid(activeKeypairClass); // if pigs can fly, then bddap is Gorgadon const gorg = { @@ -445,7 +452,8 @@ describe('Composite claim soundness checker', () => { compositeClaim, ); }, 30000); -}); + }, +); // takes a verifiable presentation and rules, returns all claims which are known to be true under // the given set of rules @@ -479,7 +487,7 @@ function getSampleKey(randomDID, keypair) { return { id: `${randomDID}#keys-1`, controller: randomDID, - type: 'EcdsaSecp256k1VerificationKey2019', + type: keypair.constructor.VerKeyType, keypair, thisisstring: 'yes', publicKey: keypair.publicKey(), @@ -489,7 +497,7 @@ function getSampleKey(randomDID, keypair) { // newDid imported from tests/utils/did-helpers.js async function validCredential() { - const { did: issuer, suite: kp } = await newDid(); + const { did: issuer, suite: kp } = await newDid(activeKeypairClass); const cred = { '@context': [ 'https://www.w3.org/2018/credentials/v1', @@ -512,7 +520,7 @@ async function validCredential() { /// makes an unsigned presentation async function validPresentation() { const creds = [await validCredential()]; - const { did: holder } = await newDid(); + const { did: holder } = await newDid(activeKeypairClass); const presentation = createPresentation( creds, `urn:${randomAsHex(16)}`, diff --git a/packages/credential-sdk/tests/data/test-keys.js b/packages/credential-sdk/tests/data/test-keys.js index 96d6b1764..ebe14d738 100644 --- a/packages/credential-sdk/tests/data/test-keys.js +++ b/packages/credential-sdk/tests/data/test-keys.js @@ -1,4 +1,4 @@ -import { Secp256k1Keypair } from "../../src/keypairs"; +import { Secp256k1Keypair, Secp256r1Keypair } from "../../src/keypairs"; import { Bls12381BBSKeyPairDock2023, Bls12381G2KeyPairDock2022, @@ -11,6 +11,9 @@ import { const keypairEcdsaSecp256k1 = new Secp256k1Keypair( "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" ); +const keypairEcdsaSecp256r1 = new Secp256r1Keypair( + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" +); const bbsPublicKeyBase58 = "24wuq4w44W7dpvtz6RCRzrmrAm3mfzwkJApR7N2spya85BkhmxzmkT3KfTQnYrZp3dUF3nAaF8EcPgM4wwAEMjMjU8h5w3t3u6JX7wdT8KZGnEsdo8UWv6SdADKDf3RtqbYC"; const bbsPrivateKeyBase58 = "HTgG6R8vFKTjf19TxgX2KsEAxKpTRvZ6VXuGQjpWKkJz"; const bbsPlusPublicKeyBase58 = "rBXz1saXxcQkiHxsPYwW6Zzi4AJH29iyW1zkf6xQsSTNrtWStmeo7DqgAqrWufjQ6H7HWdMDCv1wir6yQw5RaSJgdC4huy36vXYWgWBEhLDJrUne8oot8KDQvH5QpG91QNJ"; @@ -58,6 +61,16 @@ export default [ publicKey: keypairEcdsaSecp256k1.publicKey(), }, }, + { + sigType: "EcdsaSecp256r1Signature2019", + keyDocument: { + id: "urn:EcdsaSecp256r1VerificationKey2019#keys-1", + controller: "urn:EcdsaSecp256r1VerificationKey2019", + type: "EcdsaSecp256r1VerificationKey2019", + keypair: keypairEcdsaSecp256r1, + publicKey: keypairEcdsaSecp256r1.publicKey(), + }, + }, { sigType: "Bls12381BBSSignatureDock2023", customDidKey: true, diff --git a/packages/credential-sdk/tests/did.test.js b/packages/credential-sdk/tests/did.test.js index 8dbf42ce8..bfc1d6df7 100644 --- a/packages/credential-sdk/tests/did.test.js +++ b/packages/credential-sdk/tests/did.test.js @@ -4,6 +4,7 @@ import { DockDidOrDidMethodKey, DockDid, DidMethodKey } from "../src/types/did"; import { DidMethodKeyBytePrefixBBS23, DidMethodKeyBytePrefixBBSPlus, + DidMethodKeyBytePrefixSecp256r1, } from "../src/types/did/onchain/constants"; import { Bls12381BBS23DockVerKeyName, @@ -46,6 +47,17 @@ describe("`DockDidOrDidMethodKey.from`", () => { ).toThrowErrorMatchingSnapshot(); }); + test("`DidMethodKey.from` work for a raw did:key secp256r1", () => { + const bytes = + "0x03874c15c7fda20e539c6e5ba573c139884c351188799f5458b4b41f7924f235cd"; + const did = encodeAsBase58btc(DidMethodKeyBytePrefixSecp256r1, bytes); + const result = DidMethodKey.from(did); + expect(result.didMethodKey.secp256r1.value).toEqual(bytes); + expect(result.toString()).toEqual(`did:key:${did}`); + + expect(() => DockDidOrDidMethodKey.from(did)).toThrowErrorMatchingSnapshot(); + }); + test("`DockDidOrDidMethodKey.from`/`DockDid.from` work for did:dock", () => { const classes = [DockDidOrDidMethodKey, DockDid]; @@ -75,6 +87,22 @@ describe("`DockDidOrDidMethodKey.from`", () => { } }); + test("`DockDidOrDidMethodKey.from`/`DidMethodKey.from` works for did:key secp256r1", () => { + const classes = [DockDidOrDidMethodKey, DidMethodKey]; + const bytes = + "0x03874c15c7fda20e539c6e5ba573c139884c351188799f5458b4b41f7924f235cd"; + const did = `did:key:${encodeAsBase58btc( + DidMethodKeyBytePrefixSecp256r1, + bytes + )}`; + + for (const Did of classes) { + const result = Did.from(did); + expect(result.didMethodKey.secp256r1.value).toEqual(bytes); + expect(result.toString()).toEqual(did); + } + }); + test("`DockDidOrDidMethodKey.from`/`DidMethodKey.from` works for did:key ed25519", () => { const classes = [DockDidOrDidMethodKey, DidMethodKey]; diff --git a/packages/credential-sdk/tests/keypairs.test.js b/packages/credential-sdk/tests/keypairs.test.js index 1ff437d3b..626233d62 100644 --- a/packages/credential-sdk/tests/keypairs.test.js +++ b/packages/credential-sdk/tests/keypairs.test.js @@ -1,7 +1,7 @@ -import { Ed25519Keypair, Secp256k1Keypair } from "../src/keypairs"; +import { Ed25519Keypair, Secp256k1Keypair, Secp256r1Keypair } from "../src/keypairs"; import { randomAsHex } from "../src/utils"; -describe.each([Ed25519Keypair, Secp256k1Keypair])("Keypairs", (Keypair) => { +describe.each([Ed25519Keypair, Secp256k1Keypair, Secp256r1Keypair])("Keypairs", (Keypair) => { const createKp = (source) => Keypair === Ed25519Keypair ? Keypair.fromSeed(source) diff --git a/packages/credential-sdk/tests/pex-utils.test.js b/packages/credential-sdk/tests/pex-utils.test.js index a74f245c7..0ba15e70c 100644 --- a/packages/credential-sdk/tests/pex-utils.test.js +++ b/packages/credential-sdk/tests/pex-utils.test.js @@ -41,6 +41,7 @@ const samplePresentationDefinition = { proof_type: [ "JsonWebSignature2020", "EcdsaSecp256k1Signature2019", + "EcdsaSecp256r1Signature2019", "Ed25519Signature2018", "Bls12381BBS+SignatureDock2022", ], diff --git a/packages/credential-sdk/tests/utils.test.js b/packages/credential-sdk/tests/utils.test.js index 4e752965e..76d75d7ef 100644 --- a/packages/credential-sdk/tests/utils.test.js +++ b/packages/credential-sdk/tests/utils.test.js @@ -4,8 +4,10 @@ import { MemoizedPromiseMap, retry, timeout } from "../src/utils/async"; import { PublicKeyEd25519, PublicKeySecp256k1, + PublicKeySecp256r1, SignatureEd25519, SignatureSecp256k1, + SignatureSecp256r1, } from "../src/types"; import { isHexWithGivenByteSize } from "../src/utils/types/bytes"; import { expandJSONLD } from "../src/vc"; @@ -13,7 +15,7 @@ import { getCredentialStatus, isAccumulatorRevocationStatus, } from "../src/vc/revocation"; -import { Ed25519Keypair, Secp256k1Keypair } from "../src/keypairs"; +import { Ed25519Keypair, Secp256k1Keypair, Secp256r1Keypair } from "../src/keypairs"; import { chunks } from "../src/utils"; describe("`chunks`", () => { @@ -288,6 +290,12 @@ describe("Testing public key and signature instantiation from keyring", () => { expect(pk instanceof PublicKeySecp256k1).toBe(true); }); + test("Pair's publicKey returns correct public key from secp256r1 pair", () => { + const pair = Secp256r1Keypair.random(); + const pk = pair.publicKey(); + expect(pk instanceof PublicKeySecp256r1).toBe(true); + }); + test("Pair's sign method returns correct signature from ed25519 pair", () => { const pair = Ed25519Keypair.random(); const sig = pair.sign([1, 2]); @@ -299,6 +307,12 @@ describe("Testing public key and signature instantiation from keyring", () => { const sig = pair.sign([1, 2]); expect(sig instanceof SignatureSecp256k1).toBe(true); }); + + test("Pair's sign method returns correct signature from secp256r1 pair", () => { + const pair = Secp256r1Keypair.random(); + const sig = pair.sign([1, 2]); + expect(sig instanceof SignatureSecp256r1).toBe(true); + }); }); describe("Testing Ecdsa with secp256k1", () => { @@ -340,6 +354,45 @@ describe("Testing Ecdsa with secp256k1", () => { }); }); +describe("Testing Ecdsa with secp256r1", () => { + test("Signing and verification works", () => { + const msg = [ + 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, + 2, 3, 4, 5, 6, 7, 8, + ]; + const entropy = + "0x4c94485e0c21ae6c41ce1dfe7b6bfaceea5ab68e40a2476f50208e526f506080"; + const pair = new Secp256r1Keypair(entropy); + const pk = pair.publicKey(); + const sig = new Uint8Array( + pair.keyPair.sign(Secp256r1Keypair.hash(msg)).toDER() + ); + expect(Secp256r1Keypair.verify(msg, sig, pk)).toBe(true); + + const msg1 = [ + 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, + 2, 3, 4, 5, 6, 7, 8, 9, + ]; + const sig1 = new Uint8Array( + pair.keyPair.sign(Secp256r1Keypair.hash(msg1)).toDER() + ); + expect(Secp256r1Keypair.verify(msg1, sig1, pk)).toBe(true); + expect(msg !== msg1).toBe(true); + expect(sig !== sig1).toBe(true); + + const msg2 = [ + 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, + 2, 3, 4, 5, 6, 7, + ]; + const sig2 = new Uint8Array( + pair.keyPair.sign(Secp256r1Keypair.hash(msg2)).toDER() + ); + expect(Secp256r1Keypair.verify(msg2, sig2, pk)).toBe(true); + expect(msg2 !== msg1).toBe(true); + expect(sig2 !== sig1).toBe(true); + }); +}); + describe("Detecting accumulator status", () => { test("works", async () => { const credential = { diff --git a/packages/credential-sdk/tests/utils/did-helpers.js b/packages/credential-sdk/tests/utils/did-helpers.js index f731e7352..5d209f98d 100644 --- a/packages/credential-sdk/tests/utils/did-helpers.js +++ b/packages/credential-sdk/tests/utils/did-helpers.js @@ -1,6 +1,6 @@ import b58 from 'bs58'; import { randomAsHex } from '../../src/utils'; -import { Secp256k1Keypair } from '../../src/keypairs'; +import { Secp256k1Keypair, Secp256r1Keypair } from '../../src/keypairs'; import { verifyCredential, verifyPresentation } from '../../src/vc'; import { documentLoader, addDocument, registered } from './cached-document-loader'; @@ -53,15 +53,19 @@ export function getSampleKey(randomDID, keypair) { return { id: `${randomDID}#keys-1`, controller: randomDID, - type: 'EcdsaSecp256k1VerificationKey2019', + type: keypair.constructor.VerKeyType, keypair, thisisstring: 'yes', publicKey: keypair.publicKey(), }; } -export async function newDid() { - const kp = Secp256k1Keypair.random(); +export async function newDid(KeypairClass = Secp256k1Keypair) { + if (![Secp256k1Keypair, Secp256r1Keypair].includes(KeypairClass)) { + throw new Error(`Unsupported keypair class \`${KeypairClass?.name}\``); + } + + const kp = KeypairClass.random(); const randomDID = genPlaceholderDID(); const keypair = getSampleKey(randomDID, kp); registerDid(randomDID, keypair); diff --git a/packages/credential-sdk/tests/utils/network-cache.js b/packages/credential-sdk/tests/utils/network-cache.js index cc3849565..52b49e7ec 100644 --- a/packages/credential-sdk/tests/utils/network-cache.js +++ b/packages/credential-sdk/tests/utils/network-cache.js @@ -118,6 +118,19 @@ export default { assertionMethod: ["urn:EcdsaSecp256k1VerificationKey2019#keys-1"], authentication: ["urn:EcdsaSecp256k1VerificationKey2019#keys-1"], }, + "urn:EcdsaSecp256r1VerificationKey2019#keys-1": { + id: "urn:EcdsaSecp256r1VerificationKey2019#keys-1", + type: "EcdsaSecp256r1VerificationKey2019", + publicKeyBase58: "xPFeecydprLrZ8N9WsSfbcRzp8UifrhBkMWuJofAsvpH", + "@context": "https://w3id.org/security/v2", + controller: "urn:EcdsaSecp256r1VerificationKey2019", + }, + "urn:EcdsaSecp256r1VerificationKey2019": { + "@context": "https://w3id.org/security/v2", + id: "urn:EcdsaSecp256r1VerificationKey2019", + assertionMethod: ["urn:EcdsaSecp256r1VerificationKey2019#keys-1"], + authentication: ["urn:EcdsaSecp256r1VerificationKey2019#keys-1"], + }, "urn:JsonWebKey2020": { "@context": "https://w3id.org/security/v2", diff --git a/packages/credential-sdk/tests/utils/test-keys.js b/packages/credential-sdk/tests/utils/test-keys.js index 84657df27..0c9ce47c0 100644 --- a/packages/credential-sdk/tests/utils/test-keys.js +++ b/packages/credential-sdk/tests/utils/test-keys.js @@ -1,8 +1,11 @@ -import { Secp256k1Keypair } from "../../src/keypairs"; +import { Secp256k1Keypair, Secp256r1Keypair } from "../../src/keypairs"; const keypairEcdsaSecp256k1 = new Secp256k1Keypair( "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" ); +const keypairEcdsaSecp256r1 = new Secp256r1Keypair( + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" +); // TODO: add more testing keys (ed25519 etc) export default [ @@ -38,4 +41,14 @@ export default [ publicKey: keypairEcdsaSecp256k1.publicKey(), }, }, + { + sigType: "EcdsaSecp256r1Signature2019", + keyDocument: { + id: "urn:EcdsaSecp256r1VerificationKey2019#keys-1", + controller: "urn:EcdsaSecp256r1VerificationKey2019", + type: "EcdsaSecp256r1VerificationKey2019", + keypair: keypairEcdsaSecp256r1, + publicKey: keypairEcdsaSecp256r1.publicKey(), + }, + }, ]; diff --git a/scripts/bench/CHANGELOG.md b/scripts/bench/CHANGELOG.md index d476ff20c..ae231f977 100644 --- a/scripts/bench/CHANGELOG.md +++ b/scripts/bench/CHANGELOG.md @@ -1,5 +1,14 @@ # @docknetwork/benchmarks +## 0.4.24 + +### Patch Changes + +- Updated dependencies + - @docknetwork/credential-sdk@0.55.0 + - @docknetwork/cheqd-blockchain-api@5.0.0 + - @docknetwork/cheqd-blockchain-modules@5.0.0 + ## 0.4.23 ### Patch Changes diff --git a/scripts/bench/package.json b/scripts/bench/package.json index 738747e4d..b2851006f 100644 --- a/scripts/bench/package.json +++ b/scripts/bench/package.json @@ -2,14 +2,14 @@ "name": "@docknetwork/benchmarks", "private": true, "type": "module", - "version": "0.4.23", + "version": "0.4.24", "scripts": { "bench": "babel-node src/main.js" }, "dependencies": { - "@docknetwork/cheqd-blockchain-api": "4.2.2", - "@docknetwork/cheqd-blockchain-modules": "4.0.9", - "@docknetwork/credential-sdk": "0.54.19", + "@docknetwork/cheqd-blockchain-api": "5.0.0", + "@docknetwork/cheqd-blockchain-modules": "5.0.0", + "@docknetwork/credential-sdk": "0.55.0", "@docknetwork/crypto-wasm-ts": "^0.63.0" }, "devDependencies": {