anon-identity
Version:
Decentralized identity framework with DIDs, Verifiable Credentials, and privacy-preserving selective disclosure
230 lines • 8.88 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.BbsBlsSignature2020Suite = void 0;
const bbs_signatures_1 = require("@mattrglobal/bbs-signatures");
const signature_suite_1 = require("./signature-suite");
/**
* BbsBlsSignature2020 implementation
* Supports selective disclosure of attributes
*/
class BbsBlsSignature2020Suite extends signature_suite_1.SignatureSuite {
constructor(options = {}) {
super(options);
this.type = 'BbsBlsSignature2020';
this.requiredKeyType = signature_suite_1.KeyType.BLS12381G2;
this.supportsSelectiveDisclosure = true;
}
/**
* Create a BBS+ signature proof
*/
async createProof(options) {
try {
// 1. Create proof metadata
const proofMetadata = this.createProofMetadata(options);
// 2. Canonicalize and prepare messages
const messages = await this.prepareMessages(options.document);
// 3. Create signature
const signRequest = {
keyPair: {
secretKey: options.privateKey,
publicKey: new Uint8Array(0), // Will be derived from secret key
messageCount: messages.length
},
messages
};
const signature = await (0, bbs_signatures_1.blsSign)(signRequest);
// 4. Create the final proof
const proof = {
...proofMetadata,
proofValue: Buffer.from(signature).toString('base64')
};
return proof;
}
catch (error) {
throw new Error(`Failed to create BbsBlsSignature2020: ${error}`);
}
}
/**
* Verify a BBS+ signature proof
*/
async verifyProof(options) {
try {
// 1. Validate proof metadata
const metadataValidation = this.validateProofMetadata(options.proof, options);
if (!metadataValidation.valid) {
return false;
}
// 2. Extract signature
if (!options.proof.proofValue) {
return false;
}
const signature = Buffer.from(options.proof.proofValue, 'base64');
// 3. Prepare messages
const messages = await this.prepareMessages(options.document);
// 4. Verify signature
const verifyRequest = {
publicKey: options.publicKey,
messages,
signature
};
const { verified } = await (0, bbs_signatures_1.blsVerify)(verifyRequest);
return verified;
}
catch (error) {
console.error('BbsBlsSignature2020 verification error:', error);
return false;
}
}
/**
* Create a derived proof with selective disclosure
*/
async createDerivedProof(options) {
try {
// 1. Extract original signature
if (!options.proof.proofValue) {
throw new Error('Original proof missing proofValue');
}
const signature = Buffer.from(options.proof.proofValue, 'base64');
// 2. Prepare all messages and determine revealed indices
const allMessages = await this.prepareMessages(options.document);
const revealedIndices = await this.getRevealedIndices(options.document, options.revealedAttributes);
// 3. Create nonce
const nonce = options.nonce || this.generateNonce();
// 4. Extract public key from verification method
const publicKey = await this.extractPublicKey(options.proof.verificationMethod);
// 5. Create derived proof
const proofRequest = {
signature,
publicKey,
messages: allMessages,
revealed: revealedIndices,
nonce: Buffer.from(nonce)
};
const derivedProof = await (0, bbs_signatures_1.blsCreateProof)(proofRequest);
// 6. Create proof object
const proof = {
type: 'BbsBlsSignatureProof2020',
created: new Date().toISOString(),
verificationMethod: options.proof.verificationMethod,
proofPurpose: options.proof.proofPurpose,
proofValue: Buffer.from(derivedProof).toString('base64'),
nonce,
revealedAttributes: options.revealedAttributes
};
return proof;
}
catch (error) {
throw new Error(`Failed to create BBS+ derived proof: ${error}`);
}
}
/**
* Verify a derived proof
*/
async verifyDerivedProof(options) {
try {
// 1. Check proof type
if (options.proof.type !== 'BbsBlsSignatureProof2020') {
return false;
}
// 2. Extract proof value
if (!options.proof.proofValue) {
return false;
}
const proof = Buffer.from(options.proof.proofValue, 'base64');
// 3. Extract nonce
if (!options.proof.nonce) {
return false;
}
const nonce = Buffer.from(options.proof.nonce);
// 4. Prepare revealed messages
const revealedMessages = await this.prepareRevealedMessages(options.document, options.proof.revealedAttributes || []);
// 5. Get revealed indices
const revealedIndices = await this.getRevealedIndices(options.document, options.proof.revealedAttributes || []);
// 6. Verify derived proof
const verifyRequest = {
proof,
publicKey: options.publicKey,
messages: Array.from(revealedMessages.values()),
nonce
};
const { verified } = await (0, bbs_signatures_1.blsVerifyProof)(verifyRequest);
return verified;
}
catch (error) {
console.error('BBS+ derived proof verification error:', error);
return false;
}
}
/**
* Prepare messages from document for signing/verification
*/
async prepareMessages(document) {
// Canonicalize the document
const canonical = await this.canonicalizeDocument(document);
// Split into statements (lines)
const statements = canonical.split('\n').filter(s => s.length > 0);
// Convert each statement to bytes
return statements.map(stmt => new TextEncoder().encode(stmt));
}
/**
* Get indices of revealed attributes
*/
async getRevealedIndices(document, revealedAttributes) {
// This is a simplified implementation
// In practice, you'd map attribute paths to statement indices
const canonical = await this.canonicalizeDocument(document);
const statements = canonical.split('\n').filter(s => s.length > 0);
const indices = [];
// For each revealed attribute, find matching statements
for (const attr of revealedAttributes) {
statements.forEach((stmt, idx) => {
if (stmt.includes(attr)) {
indices.push(idx);
}
});
}
return [...new Set(indices)].sort((a, b) => a - b);
}
/**
* Prepare revealed messages for derived proof verification
*/
async prepareRevealedMessages(document, revealedAttributes) {
const messages = await this.prepareMessages(document);
const indices = await this.getRevealedIndices(document, revealedAttributes);
const revealedMessages = new Map();
for (const idx of indices) {
if (idx < messages.length) {
revealedMessages.set(idx, messages[idx]);
}
}
return revealedMessages;
}
/**
* Extract public key from verification method
*/
async extractPublicKey(verificationMethod) {
// In a real implementation, this would resolve the DID and extract the key
// For now, we'll throw an error
throw new Error('Public key extraction from DID not implemented');
}
/**
* Generate a random nonce
*/
generateNonce() {
const bytes = new Uint8Array(32);
crypto.getRandomValues(bytes);
return Buffer.from(bytes).toString('base64');
}
/**
* Generate a BLS12-381 G2 key pair
*/
static async generateKeyPair() {
const keyPair = await (0, bbs_signatures_1.generateBls12381G2KeyPair)();
return {
publicKey: keyPair.publicKey,
privateKey: keyPair.secretKey
};
}
}
exports.BbsBlsSignature2020Suite = BbsBlsSignature2020Suite;
//# sourceMappingURL=bbs-bls-signature-2020.js.map