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