Skip to content

Commit

Permalink
Include blind factor for issuer-known pseudonyms and debugging output.
Browse files Browse the repository at this point in the history
  • Loading branch information
dlongley committed Aug 15, 2024
1 parent ccd5ae7 commit 63acf90
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 26 deletions.
16 changes: 12 additions & 4 deletions lib/bbs/blind/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,20 +34,25 @@ export function CoreBlindSign({
1. L = length(message_scalars)
2. (msg_1, ..., msg_L) = message_scalars
3. (Q_1, H_1, ..., H_L) = generators
4. Q_2 = Identity_G1
5. if length(blind_generators) > 0, Q_2 = blind_generators[0]
6. commit = deserialize_and_validate_commit(commitment_with_proof,
// FIX to spec: blind_generators is always > 0
//4. Q_2 = Identity_G1
//5. if length(blind_generators) > 0, Q_2 = blind_generators[0]
4. Q_2 = blind_generators[0]
5. commit = deserialize_and_validate_commit(commitment_with_proof,
blind_generators, api_id)
7. if commit is INVALID, return INVALID
6. if commit is INVALID, return INVALID
*/
const L = message_scalars.length;
const msgs = message_scalars.slice(0, L);
const {Q_1} = generators;
const H = generators.H.slice(0, L);
console.log('H count', H.length);
// Identity_G1 == ciphersuite.Identity_E1
const Q_2 = blind_generators.length === 0 ?
ciphersuite.Identity_E1 : blind_generators[0];
// FIXME: determine which to use
//const Q_2 = blind_generators[0];
const commitment = deserialize_and_validate_commit({
commitment_with_proof, blind_generators, api_id, ciphersuite
});
Expand All @@ -59,6 +64,9 @@ export function CoreBlindSign({
2. e_octs = serialize((SK, commitment_with_proof, signer_blind,
msg_1, ..., msg_L, domain))
3. e = BBS.hash_to_scalar(e_octs, hash_to_scalar_dst)
// FIX to spec: remove/change the following comment, it should be when there
// is no commitment that the `signer_blind` should just be zero and that's
// why the commitment won't be changed, the "following comment" is below:
// if a commitment is not supplied, Q_2 = Identity_G1, meaning that
// signer_blind will be ignored.
4. commit = commit + Q_2 * signer_blind
Expand Down
45 changes: 45 additions & 0 deletions lib/bbs/proof.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ export function ProofFinalize({
const mHat = undisclosed_messages.map(
(undisclosed, j) => Fr.add(m_j[j], Fr.mul(undisclosed, challenge)));
const proof = [Abar, Bbar, D, eHat, r1Hat, r3Hat, ...mHat, challenge];
console.log('all the commitments', mHat.map(c => c.toString(16)));
console.log('total number of committments', mHat.length);
return proof_to_octets({proof, ciphersuite});
}

Expand All @@ -148,12 +150,18 @@ export function ProofInit({
*/
const [A, e] = signature_result;
const {H} = generators;
const L = messages.length;
const U = undisclosed_indexes.length;
if(random_scalars.length !== (U + 5)) {
throw new Error(
`"random_scalars.length" (${random_scalars.length}) must equal ` +
`"undisclosed_indexes.length + 5" (${U + 5}).`);
}
if(generators.length !== (L + 1)) {
throw new Error(
`"generators.length" (${generators.length}) must equal the ` +
`total number of messages + 1 (${L + 1}).`);
}

/* Algorithm:
Expand All @@ -171,6 +179,8 @@ export function ProofInit({
const {B, domain} = calculate_B({
PK, generators, header, messages, api_id, ciphersuite
});
console.log('proof init generated B', B.toHex());
console.log('proof init generated domain', domain.toString(16));
// `e~` expressed as `e_` here, `m~_j1` as `m_[0]`, etc. ...
const [r1, r2, e_, r1_, r3_, ...m_j] = random_scalars;
const D = B.multiply(r2);
Expand All @@ -182,6 +192,11 @@ export function ProofInit({
for(const [i, j] of undisclosed_indexes.entries()) {
T2 = T2.add(H[j].multiply(m_j[i]));
}
console.log('Abar', Abar.toHex());
console.log('Bbar', Bbar.toHex());
console.log('D', D.toHex());
console.log('T1', T1.toHex());
console.log('T2', T2.toHex());
return [Abar, Bbar, D, T1, T2, domain];
}

Expand Down Expand Up @@ -213,13 +228,19 @@ export function ProofVerifyInit({
const [Abar, Bbar, D, eHat, r1Hat, r3Hat, ...commitments] = proof;
const c = commitments.pop();
const U = commitments.length;
console.log('commitments', commitments.map(c => c.toString(16)));
const R = disclosed_indexes.length;
const L = R + U;
console.log('R', R);
console.log('U', U);
console.log('L', L);
if(disclosed_indexes.some(i => isNaN(i) || i < 0 || i > (L - 1))) {
throw new Error(
`Every index in "disclosed_indexes" must be a number >= 0 and ` +
`<= ${L}.`);
}
// FIXME: blind proof gen that *always* includes a blind generator even
// with no committed message creates a problem for this check
if(generators.length !== (L + 1)) {
throw new Error(
`"generators.length" (${generators.length}) must equal the ` +
Expand All @@ -243,18 +264,42 @@ export function ProofVerifyInit({
const domain = calculate_domain({
PK, generators, header, api_id, ciphersuite
});
console.log('proof verify init generated domain', domain.toString(16));
const T1 = Bbar.multiply(c).add(Abar.multiply(eHat)).add(D.multiply(r1Hat));
const {P1} = ciphersuite;
console.log('P1', P1.toHex());
console.log('Q_1', Q_1.toHex());
console.log('domain', domain.toString(16));
let Bv = P1.add(Q_1.multiply(domain));
// for each disclosed message, add matching generator * message
for(const [i, msg_i] of disclosed_messages.entries()) {
Bv = Bv.add(H[disclosed_indexes[i]].multiply(msg_i));
}
console.log('number of disclosed_messages', disclosed_messages.length);
console.log('Bv', Bv.toHex());
console.log('c', c.toString(16));
console.log('D', D.toHex());
console.log('r3Hat', r3Hat.toString(16));
let T2 = Bv.multiply(c).add(D.multiply(r3Hat));
// for each commitment (each for an undisclosed message),
// add matching generator * commitment
console.log('number of commitments', commitments.length);
for(const [j, mHat_j] of commitments.entries()) {
T2 = T2.add(H[undisclosed_indexes[j]].multiply(mHat_j));
}
/*
"A": "ad5d4ff88f21c3995c5ffffe85c3cf12c1da9af6569f7cf498b59bb6bbcb792abd739abf28ecad3afc7f31f43c1c496c",

Check failure on line 291 in lib/bbs/proof.js

View workflow job for this annotation

GitHub Actions / lint (20.x)

This line has a length of 108. Maximum allowed is 80
"Abar": "b842263b0948604f224f7fa512aa28adb84747e55cf1fb68c1fe1df935a7baf549f272fa960f108e5700b11607aeb0d2",

Check failure on line 292 in lib/bbs/proof.js

View workflow job for this annotation

GitHub Actions / lint (20.x)

This line has a length of 111. Maximum allowed is 80
"B": "b822ddc4e5f6f7e6926322c1b973614fc93366eb0eafb7de44c72a2b5cd8109f61c698d42c959aac590c6e05b74b5b1e",

Check failure on line 293 in lib/bbs/proof.js

View workflow job for this annotation

GitHub Actions / lint (20.x)

This line has a length of 108. Maximum allowed is 80
"Bbar": "abb8ca4d57b79d632df956fbdad0a803ca1952077c70b3b028bae10d5c9f3f8aec51db8782f24437ed93ae6ee020ffae",

Check failure on line 294 in lib/bbs/proof.js

View workflow job for this annotation

GitHub Actions / lint (20.x)

This line has a length of 111. Maximum allowed is 80
"D": "a22a52d03abaaf3e0bf1cd374e7d9bbcbcbd3118b2086bcacd28298a8b277fdd78b5635ae3a153ee3b9c85edfa43428f",

Check failure on line 295 in lib/bbs/proof.js

View workflow job for this annotation

GitHub Actions / lint (20.x)

This line has a length of 108. Maximum allowed is 80
"T1": "b62508ef7e2e93d42e16620ceb49248f87abb6158cd91152c31332629ae2a2aad0b38e0dd9b53b19229a2466c6b4d498",

Check failure on line 296 in lib/bbs/proof.js

View workflow job for this annotation

GitHub Actions / lint (20.x)

This line has a length of 109. Maximum allowed is 80
"T2": "ae911d0401a48bd09c7e3f671b58ecea21cf7211e5e84561ade54a31e596f56a5d3a00bfb8677e1080fbb7327011a8f4",

Check failure on line 297 in lib/bbs/proof.js

View workflow job for this annotation

GitHub Actions / lint (20.x)

This line has a length of 109. Maximum allowed is 80
*/
console.log('Abar', Abar.toHex());
console.log('Bbar', Bbar.toHex());
console.log('D', D.toHex());
console.log('T1', T1.toHex());
console.log('T2', T2.toHex());
return [Abar, Bbar, D, T1, T2, domain];
}
24 changes: 20 additions & 4 deletions lib/bbs/pseudonym/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Copyright (c) 2023-2024 Digital Bazaar, Inc. All rights reserved.
*/
import {
calculate_random_scalars,
calculate_random_scalars, concatGenerators,
mocked_calculate_random_scalars,
octets_to_proof, octets_to_pubkey, octets_to_signature
} from '../util.js';
Expand All @@ -23,6 +23,8 @@ export async function CoreProofGenWithPseudonym({
messages = [], disclosed_indexes = [],
api_id = new Uint8Array(), ciphersuite, mocked_random_scalars_options
} = {}) {
console.log('generator length', generators.length);
console.log('proofgen generators', generators.map(g => g.toHex()));
/* Note: The only difference between `CoreProofGenWithPseudonym` and
`CoreProofGen` is the generation of `pseudo_init_res` to be passed to
`ProofWithPseudonymChallengeCalculate`. */
Expand Down Expand Up @@ -110,7 +112,8 @@ export async function CoreProofGenWithPseudonym({
// generate `pseudonym_init_res`
const OP = ciphersuite.hash_to_curve_g1(verifier_id, api_id);
// `pid_` means `pid~` here
const pid_ = random_scalars.at(-1);
console.log('U+5', U+5, 'length', random_scalars.length);

Check failure on line 115 in lib/bbs/pseudonym/core.js

View workflow job for this annotation

GitHub Actions / lint (20.x)

Operator '+' must be spaced
const pid_ = random_scalars.at(-2);
const Ut = OP.multiply(pid_);
const pseudonym_init_res = [pseudonym, OP, Ut];
// generate challenge
Expand All @@ -128,7 +131,7 @@ export async function CoreProofGenWithPseudonym({
export function CoreProofVerifyWithPseudonym({
PK, proof,
pseudonym, verifier_id,
generators,
generators, blind_generators,
header = new Uint8Array(), ph = new Uint8Array(),
disclosed_messages = [], disclosed_indexes = [],
api_id = new Uint8Array(), ciphersuite
Expand Down Expand Up @@ -157,15 +160,24 @@ export function CoreProofVerifyWithPseudonym({
return INVALID
*/
generators = concatGenerators(generators, blind_generators);
console.log('verify generators length', generators.length);
console.log('verify generators', generators.map(g => g.toHex()));
const proof_result = octets_to_proof({proof_octets: proof, ciphersuite});
const [Abar, Bbar] = proof_result;
// `pid^` used below is the last commitment
const pidHat = proof_result.at(-2);
// FIX to spec: `pid^` is the last commitment when there is more than 1
// blind generator and second to last otherwise
console.log('blind_generators.length', blind_generators.length);
const pidHat = proof_result.at(blind_generators.length > 1 ? -2 : -3);
const c = proof_result.at(-1);
console.log('proof_results', proof_result.slice(6).map(c => c.toString(16)));
const W = octets_to_pubkey({PK, ciphersuite});
const R = disclosed_indexes.length;
// length of commitments (proof_result has 7 values other than commitments)
const U = proof_result.length - 7;
console.log('verify proof R', R);
console.log('verify proof U', U);
if(disclosed_indexes.some(i => isNaN(i) || i < 0 || i > (R + U - 1))) {
throw new Error(
`Every index in "disclosed_indexes" (${disclosed_indexes}) ` +
Expand Down Expand Up @@ -206,6 +218,9 @@ export function CoreProofVerifyWithPseudonym({
});
if(c !== challenge) {
// proof challenge does not match
console.log('challenge does not match');
console.log('c', c.toString(16));
console.log('challenge', challenge.toString(16));
return false;
}
// performs step 9 more efficiently;
Expand All @@ -214,5 +229,6 @@ export function CoreProofVerifyWithPseudonym({
const {BP2} = ciphersuite;
const pair1 = [Abar, W];
const pair2 = [Bbar, BP2];
console.log('pairing does not match');
return ciphersuite.pairingCompare({pair1, pair2});
}
49 changes: 40 additions & 9 deletions lib/bbs/pseudonym/interface.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,22 +207,35 @@ export async function ProofGenWithPseudonym({
// FIX to spec: unnecessary duplicate computation of `pid_scalar`
3. pid_scalar = messages_to_scalars((pid), api_id)
4. generators = create_generators(length(messages) + 1, api_id)
5. proof = CoreProofGenWithPseudonym(
PK, signature, pseudonym, verifier_id, generators,
// FIX to spec: always include a blind generator for the pseudonym
5. blind_generators = BBS.create_generators(1, "BLIND_" || api_id)
6. proof = CoreProofGenWithPseudonym(
PK, signature, pseudonym, verifier_id,
generators.append(blind_generators),
header, ph, message_scalars, disclosed_indexes, api_id)
6. if proof is INVALID, return INVALID
7. return proof
7. if proof is INVALID, return INVALID
8. return proof
*/
messages = [...messages, pid];
const message_scalars = messages_to_scalars({messages, api_id, ciphersuite});
const generators = create_generators({
count: messages.length + 1, api_id, ciphersuite
});
const blind_generators = create_generators({
count: 1,
api_id: prependBlindApiId({api_id}),
ciphersuite
});
// FIXME: determine if this should be done
// add `0` blind factor to message scalars as blind sign was used with
// an empty `commitment_with_message`
message_scalars.push(0n);
return CoreProofGenWithPseudonym({
PK, signature,
pseudonym, verifier_id,
generators, header, ph,
generators: concatGenerators(generators, blind_generators),
header, ph,
messages: message_scalars, disclosed_indexes, api_id, ciphersuite,
// for test suite only
mocked_random_scalars_options
Expand Down Expand Up @@ -290,15 +303,26 @@ export async function ProofVerifyWithPseudonym({
const U = remainder / octet_scalar_length;
const R = disclosed_indexes.length;
const total_no_messages = R + U - 1;
const M = total_no_messages - L;
console.log('U is ', U);
console.log('R is ', R);
console.log('L is ', L);
console.log('M would be', total_no_messages - L);
// note: M is set to a minimum of zero, see algorithm below for why.
const M = Math.max(0, total_no_messages - L);
//const M = total_no_messages - L;
pseudonym = ciphersuite.octets_to_point_E1(pseudonym);

/* Algorithm:
1. message_scalars = messages_to_scalars(disclosed_messages, api_id)
2. generators = create_generators(L + 1, api_id)
3. blind_generators = []
4. if M > -1, blind_generators = create_generators(M + 1, "BLIND_" + api_id)
// FIX to spec: since BlindSign *always* creates at least one blind
// generator, we must do the same here, forcing M to be 0 if it is less
// than 1
//3. blind_generators = []
//4. if M > -1, blind_generators = create_generators(M + 1, "BLIND_" + api_id)
3. if M > -1, M = 0
4. blind_generators = create_generators(M + 1, "BLIND_" + api_id)
5. result = CoreProofVerifyWithPseudonym(
PK, proof,
pseudonym, verifier_id,
Expand All @@ -312,7 +336,9 @@ export async function ProofVerifyWithPseudonym({
messages: disclosed_messages, api_id, ciphersuite
});
const generators = create_generators({count: L + 1, api_id, ciphersuite});
console.log('verify generator count', L + 1);
let blind_generators;
console.log('M', M);
if(M > -1) {
blind_generators = create_generators({
count: M + 1,
Expand All @@ -322,10 +348,15 @@ export async function ProofVerifyWithPseudonym({
} else {
blind_generators = [];
}
console.log('generators length', generators.length);
console.log('blind generators length', blind_generators.length);
console.log('total generators length', concatGenerators(generators, blind_generators).length);

Check failure on line 353 in lib/bbs/pseudonym/interface.js

View workflow job for this annotation

GitHub Actions / lint (20.x)

This line has a length of 96. Maximum allowed is 80
return CoreProofVerifyWithPseudonym({
PK, proof,
pseudonym, verifier_id,
generators: concatGenerators(generators, blind_generators),
//generators: concatGenerators(generators, blind_generators),
generators,
blind_generators,
header, ph,
disclosed_messages: message_scalars, disclosed_indexes,
api_id, ciphersuite
Expand Down
1 change: 1 addition & 0 deletions lib/bbs/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export function calculate_B({
});
let B = P1.add(Q_1.multiply(domain));
let i = 0;
console.log('number of messages', messages.length);
for(const message of messages) {
if(message !== 0n) {
B = B.add(H[i++].multiply(message));
Expand Down
Loading

0 comments on commit 63acf90

Please sign in to comment.