wallet-core: fix issue with crock encoding of age restrictions
This commit is contained in:
parent
d6a172c4a0
commit
ec43b6a5bf
@ -857,6 +857,13 @@ export type Edx25519PublicKey = FlavorP<Uint8Array, "Edx25519PublicKey", 32>;
|
||||
export type Edx25519PrivateKey = FlavorP<Uint8Array, "Edx25519PrivateKey", 64>;
|
||||
export type Edx25519Signature = FlavorP<Uint8Array, "Edx25519Signature", 64>;
|
||||
|
||||
export type Edx25519PublicKeyEnc = FlavorP<string, "Edx25519PublicKeyEnc", 32>;
|
||||
export type Edx25519PrivateKeyEnc = FlavorP<
|
||||
string,
|
||||
"Edx25519PrivateKeyEnc",
|
||||
64
|
||||
>;
|
||||
|
||||
/**
|
||||
* Convert a big integer to a fixed-size, little-endian array.
|
||||
*/
|
||||
@ -958,7 +965,7 @@ export interface AgeCommitment {
|
||||
/**
|
||||
* Public keys, one for each age group specified in the age mask.
|
||||
*/
|
||||
publicKeys: Edx25519PublicKey[];
|
||||
publicKeys: Edx25519PublicKeyEnc[];
|
||||
}
|
||||
|
||||
export interface AgeProof {
|
||||
@ -966,7 +973,7 @@ export interface AgeProof {
|
||||
* Private keys. Typically smaller than the number of public keys,
|
||||
* because we drop private keys from age groups that are restricted.
|
||||
*/
|
||||
privateKeys: Edx25519PrivateKey[];
|
||||
privateKeys: Edx25519PrivateKeyEnc[];
|
||||
}
|
||||
|
||||
export interface AgeCommitmentProof {
|
||||
@ -984,7 +991,7 @@ export namespace AgeRestriction {
|
||||
export function hashCommitment(ac: AgeCommitment): HashCodeString {
|
||||
const hc = new nacl.HashState();
|
||||
for (const pub of ac.publicKeys) {
|
||||
hc.update(pub);
|
||||
hc.update(decodeCrock(pub));
|
||||
}
|
||||
return encodeCrock(hc.finish().subarray(0, 32));
|
||||
}
|
||||
@ -1042,10 +1049,10 @@ export namespace AgeRestriction {
|
||||
return {
|
||||
commitment: {
|
||||
mask: ageMask,
|
||||
publicKeys: pubs,
|
||||
publicKeys: pubs.map((x) => encodeCrock(x)),
|
||||
},
|
||||
proof: {
|
||||
privateKeys: privs,
|
||||
privateKeys: privs.map((x) => encodeCrock(x)),
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -1062,8 +1069,11 @@ export namespace AgeRestriction {
|
||||
return false;
|
||||
}
|
||||
for (let i = 0; i < c1.publicKeys.length; i++) {
|
||||
const k1 = c1.publicKeys[i];
|
||||
const k2 = await Edx25519.publicKeyDerive(c2.publicKeys[i], salt);
|
||||
const k1 = decodeCrock(c1.publicKeys[i]);
|
||||
const k2 = await Edx25519.publicKeyDerive(
|
||||
decodeCrock(c2.publicKeys[i]),
|
||||
salt,
|
||||
);
|
||||
if (k1 != k2) {
|
||||
return false;
|
||||
}
|
||||
@ -1079,20 +1089,22 @@ export namespace AgeRestriction {
|
||||
const newPubs: Edx25519PublicKey[] = [];
|
||||
|
||||
for (const oldPub of commitmentProof.commitment.publicKeys) {
|
||||
newPubs.push(await Edx25519.publicKeyDerive(oldPub, salt));
|
||||
newPubs.push(await Edx25519.publicKeyDerive(decodeCrock(oldPub), salt));
|
||||
}
|
||||
|
||||
for (const oldPriv of commitmentProof.proof.privateKeys) {
|
||||
newPrivs.push(await Edx25519.privateKeyDerive(oldPriv, salt));
|
||||
newPrivs.push(
|
||||
await Edx25519.privateKeyDerive(decodeCrock(oldPriv), salt),
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
commitment: {
|
||||
mask: commitmentProof.commitment.mask,
|
||||
publicKeys: newPubs,
|
||||
publicKeys: newPubs.map((x) => encodeCrock(x)),
|
||||
},
|
||||
proof: {
|
||||
privateKeys: newPrivs,
|
||||
privateKeys: newPrivs.map((x) => encodeCrock(x)),
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -1112,7 +1124,11 @@ export namespace AgeRestriction {
|
||||
}
|
||||
const priv = commitmentProof.proof.privateKeys[group - 1];
|
||||
const pub = commitmentProof.commitment.publicKeys[group - 1];
|
||||
const sig = nacl.crypto_edx25519_sign_detached(d, priv, pub);
|
||||
const sig = nacl.crypto_edx25519_sign_detached(
|
||||
d,
|
||||
decodeCrock(priv),
|
||||
decodeCrock(pub),
|
||||
);
|
||||
return sig;
|
||||
}
|
||||
|
||||
@ -1131,7 +1147,11 @@ export namespace AgeRestriction {
|
||||
return true;
|
||||
}
|
||||
const pub = commitment.publicKeys[group - 1];
|
||||
return nacl.crypto_edx25519_sign_detached_verify(d, decodeCrock(sig), pub);
|
||||
return nacl.crypto_edx25519_sign_detached_verify(
|
||||
d,
|
||||
decodeCrock(sig),
|
||||
decodeCrock(pub),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,29 +25,29 @@
|
||||
* Imports.
|
||||
*/
|
||||
|
||||
import { codecForAmountString } from "./amounts.js";
|
||||
import {
|
||||
buildCodecForObject,
|
||||
codecForString,
|
||||
codecForList,
|
||||
codecOptional,
|
||||
codecForAny,
|
||||
codecForNumber,
|
||||
codecForBoolean,
|
||||
codecForMap,
|
||||
Codec,
|
||||
codecForConstNumber,
|
||||
buildCodecForUnion,
|
||||
Codec,
|
||||
codecForAny,
|
||||
codecForBoolean,
|
||||
codecForConstNumber,
|
||||
codecForConstString,
|
||||
codecForList,
|
||||
codecForMap,
|
||||
codecForNumber,
|
||||
codecForString,
|
||||
codecOptional,
|
||||
} from "./codec.js";
|
||||
import {
|
||||
codecForTimestamp,
|
||||
codecForDuration,
|
||||
TalerProtocolTimestamp,
|
||||
TalerProtocolDuration,
|
||||
} from "./time.js";
|
||||
import { codecForAmountString } from "./amounts.js";
|
||||
import { strcmp } from "./helpers.js";
|
||||
import { AgeCommitmentProof, Edx25519PublicKey } from "./talerCrypto.js";
|
||||
import { AgeCommitmentProof, Edx25519PublicKeyEnc } from "./talerCrypto.js";
|
||||
import {
|
||||
codecForDuration,
|
||||
codecForTimestamp,
|
||||
TalerProtocolDuration,
|
||||
TalerProtocolTimestamp,
|
||||
} from "./time.js";
|
||||
|
||||
/**
|
||||
* Denomination as found in the /keys response from the exchange.
|
||||
@ -287,7 +287,7 @@ export interface CoinDepositPermission {
|
||||
|
||||
minimum_age_sig?: EddsaSignatureString;
|
||||
|
||||
age_commitment?: Edx25519PublicKey[];
|
||||
age_commitment?: Edx25519PublicKeyEnc[];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1755,7 +1755,7 @@ export interface ExchangeRefreshRevealRequest {
|
||||
* the client MUST provide the original age commitment, i.e. the vector
|
||||
* of public keys.
|
||||
*/
|
||||
old_age_commitment?: Edx25519PublicKey[];
|
||||
old_age_commitment?: Edx25519PublicKeyEnc[];
|
||||
}
|
||||
|
||||
export interface DepositSuccess {
|
||||
|
@ -1084,7 +1084,7 @@ export const nativeCryptoR: TalerCryptoInterfaceR = {
|
||||
s.age_commitment =
|
||||
depositInfo.ageCommitmentProof?.commitment.publicKeys;
|
||||
} else if (depositInfo.ageCommitmentProof) {
|
||||
(s as any).h_age_commitment = hAgeCommitment;
|
||||
(s as any).h_age_commitment = encodeCrock(hAgeCommitment);
|
||||
}
|
||||
|
||||
return s;
|
||||
@ -1518,9 +1518,7 @@ export const nativeCryptoR: TalerCryptoInterfaceR = {
|
||||
});
|
||||
|
||||
logger.info(`payto URI: ${req.reservePayto}`);
|
||||
logger.info(
|
||||
`signing WALLET_PURSE_MERGE over ${encodeCrock(mergeSigBlob)}`,
|
||||
);
|
||||
logger.info(`signing WALLET_PURSE_MERGE over ${encodeCrock(mergeSigBlob)}`);
|
||||
|
||||
const reserveSigBlob = buildSigPS(
|
||||
TalerSignaturePurpose.WALLET_ACCOUNT_MERGE,
|
||||
|
@ -242,7 +242,7 @@ export function selectWithdrawalDenominations(
|
||||
for (const d of denoms) {
|
||||
let count = 0;
|
||||
const cost = Amounts.add(d.value, d.feeWithdraw).amount;
|
||||
for (; ;) {
|
||||
for (;;) {
|
||||
if (Amounts.cmp(remaining, cost) < 0) {
|
||||
break;
|
||||
}
|
||||
@ -903,7 +903,8 @@ export async function updateWithdrawalDenoms(
|
||||
denom.verificationStatus === DenominationVerificationStatus.Unverified
|
||||
) {
|
||||
logger.trace(
|
||||
`Validating denomination (${current + 1}/${denominations.length
|
||||
`Validating denomination (${current + 1}/${
|
||||
denominations.length
|
||||
}) signature of ${denom.denomPubHash}`,
|
||||
);
|
||||
let valid = false;
|
||||
@ -1030,7 +1031,7 @@ async function queryReserve(
|
||||
if (
|
||||
resp.status === 404 &&
|
||||
result.talerErrorResponse.code ===
|
||||
TalerErrorCode.EXCHANGE_RESERVES_STATUS_UNKNOWN
|
||||
TalerErrorCode.EXCHANGE_RESERVES_STATUS_UNKNOWN
|
||||
) {
|
||||
ws.notify({
|
||||
type: NotificationType.ReserveNotYetFound,
|
||||
@ -1336,7 +1337,7 @@ export async function getExchangeWithdrawalInfo(
|
||||
) {
|
||||
logger.warn(
|
||||
`wallet's support for exchange protocol version ${WALLET_EXCHANGE_PROTOCOL_VERSION} might be outdated ` +
|
||||
`(exchange has ${exchangeDetails.protocolVersion}), checking for updates`,
|
||||
`(exchange has ${exchangeDetails.protocolVersion}), checking for updates`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1869,6 +1870,7 @@ export async function acceptWithdrawalFromUri(
|
||||
confirmUrl: withdrawInfo.confirmTransferUrl,
|
||||
},
|
||||
},
|
||||
restrictAge: req.restrictAge,
|
||||
forcedDenomSel: req.forcedDenomSel,
|
||||
reserveStatus: ReserveRecordStatus.RegisteringBank,
|
||||
});
|
||||
|
@ -291,11 +291,14 @@ export function selectPayCoins(
|
||||
aci.denomPub.age_mask,
|
||||
req.requiredMinimumAge,
|
||||
);
|
||||
if (!aci.ageCommitmentProof) {
|
||||
// No age restriction, can't use for this payment
|
||||
continue;
|
||||
}
|
||||
if (aci.ageCommitmentProof.proof.privateKeys.length < index) {
|
||||
// if (!aci.ageCommitmentProof) {
|
||||
// // No age restriction, can't use for this payment
|
||||
// continue;
|
||||
// }
|
||||
if (
|
||||
aci.ageCommitmentProof &&
|
||||
aci.ageCommitmentProof.proof.privateKeys.length < index
|
||||
) {
|
||||
// Available age proofs to low, can't use for this payment
|
||||
continue;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user