[age-withdraw] WiP: first types and adjustments
This commit is contained in:
parent
819949d7f2
commit
70fca92e78
@ -1254,30 +1254,9 @@ export namespace AgeRestriction {
|
||||
age: number,
|
||||
): Promise<AgeCommitmentProof> {
|
||||
invariant((ageMask & 1) === 1);
|
||||
const numPubs = countAgeGroups(ageMask) - 1;
|
||||
const numPrivs = getAgeGroupIndex(ageMask, age);
|
||||
const seed = getRandomBytes(32);
|
||||
|
||||
const pubs: Edx25519PublicKey[] = [];
|
||||
const privs: Edx25519PrivateKey[] = [];
|
||||
|
||||
for (let i = 0; i < numPubs; i++) {
|
||||
const priv = await Edx25519.keyCreate();
|
||||
const pub = await Edx25519.getPublic(priv);
|
||||
pubs.push(pub);
|
||||
if (i < numPrivs) {
|
||||
privs.push(priv);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
commitment: {
|
||||
mask: ageMask,
|
||||
publicKeys: pubs.map((x) => encodeCrock(x)),
|
||||
},
|
||||
proof: {
|
||||
privateKeys: privs.map((x) => encodeCrock(x)),
|
||||
},
|
||||
};
|
||||
return restrictionCommitSeeded(ageMask, age, seed);
|
||||
}
|
||||
|
||||
const PublishedAgeRestrictionBaseKey: Edx25519PublicKey = decodeCrock(
|
||||
|
@ -1788,6 +1788,89 @@ export interface ExchangeRefreshRevealRequest {
|
||||
old_age_commitment?: Edx25519PublicKeyEnc[];
|
||||
}
|
||||
|
||||
export interface ExchangeAgeWithdrawRequest {
|
||||
// Array of n hash codes of denomination public keys to order.
|
||||
// These denominations MUST support age restriction as defined in the
|
||||
// output to /keys.
|
||||
// The sum of all denomination's values and fees MUST be at most the
|
||||
// balance of the reserve. The balance of the reserve will be
|
||||
// immediatley reduced by that amount.
|
||||
denoms_h: HashCodeString[];
|
||||
|
||||
// n arrays of kappa entries with blinded coin envelopes. Each
|
||||
// (toplevel) entry represents kappa canditates for a particular
|
||||
// coin. The exchange will respond with an index gamma, which is
|
||||
// the index that shall remain undisclosed during the reveal phase.
|
||||
// The SHA512 hash $ACH over the blinded coin envelopes is the commitment
|
||||
// that is later used as the key to the reveal-URL.
|
||||
blinded_coins_evs: CoinEnvelope[][];
|
||||
|
||||
// The maximum age to commit to. MUST be the same as the maximum
|
||||
// age value assigned to the reserve, based on its birthday date.
|
||||
max_age: number;
|
||||
|
||||
// Signature of TALER_AgeWithdrawRequestPS created with
|
||||
// the reserves's private key
|
||||
// using purpose TALER_SIGNATURE_WALLET_RESERVE_AGE_WITHDRAW.
|
||||
reserve_sig: EddsaSignatureString;
|
||||
}
|
||||
|
||||
export interface ExchangeAgeWithdrawResponse {
|
||||
// index of the commitments that the client doesn't
|
||||
// have to disclose
|
||||
noreveal_index: number;
|
||||
|
||||
// Signature of TALER_AgeWithdrawConfirmationPS whereby
|
||||
// the exchange confirms the noreveal_index.
|
||||
exchange_sig: EddsaSignatureString;
|
||||
|
||||
// Public EdDSA key of the exchange that was used to
|
||||
// generate the signature. Should match one of the exchange's signing
|
||||
// keys from /keys. Again given explicitly as the client might
|
||||
// otherwise be confused by clock skew as to which signing key was used.
|
||||
exchange_pub: EddsaPublicKeyString;
|
||||
}
|
||||
|
||||
export interface ExchangeAgeWithdrawRevealRequest {
|
||||
// Array of n of (kappa - 1) disclosed coin master secrets, from
|
||||
// which the coins' private key, blinding, nonce (for Clause-Schnorr) and
|
||||
// age-restriction is calculated.
|
||||
//
|
||||
// Given each coin's private key and age commitment, the exchange will
|
||||
// calculate each coin's blinded hash value und use all those (disclosed)
|
||||
// blinded hashes together with the non-disclosed envelopes coin_evs
|
||||
// during the verification of the original age-withdraw-commitment.
|
||||
disclosed_coin_secrets: AgeRestrictedCoinSecret[][];
|
||||
}
|
||||
|
||||
// The Master key material from which the coins' private key coin_priv,
|
||||
// blinding beta and nonce nonce (for Clause-Schnorr) itself are
|
||||
// derived as usually in wallet-core. Given a coin's master key material,
|
||||
// the age commitment for the coin MUST be derived from this private key as
|
||||
// follows:
|
||||
//
|
||||
// Let m ∈ {1,...,M} be the maximum age group as defined in the reserve
|
||||
// that the wallet can commit to.
|
||||
//
|
||||
// For age group $AG ∈ {1,...m}, set
|
||||
// seed = HDKF(coin_secret, "age-commitment", $AG)
|
||||
// p[$AG] = Edx25519_generate_private(seed)
|
||||
// and calculate the corresponding Edx25519PublicKey as
|
||||
// q[$AG] = Edx25519_public_from_private(p[$AG])
|
||||
//
|
||||
// For age groups $AG ∈ {m,...,M}, set
|
||||
// f[$AG] = HDKF(coin_secret, "age-factor", $AG)
|
||||
// and calculate the corresponding Edx25519PublicKey as
|
||||
// q[$AG] = Edx25519_derive_public(PublishedAgeRestrictionBaseKey, f[$AG])
|
||||
//
|
||||
// FIXME: shall we add some flavor to this string?
|
||||
export type AgeRestrictedCoinSecret = string;
|
||||
|
||||
export interface ExchangeAgeWithdrawRevealResponse {
|
||||
// List of the exchange's blinded RSA or CS signatures on the new coins.
|
||||
ev_sigs : BlindedDenominationSignature[];
|
||||
}
|
||||
|
||||
export interface DepositSuccess {
|
||||
// Optional base URL of the exchange for looking up wire transfers
|
||||
// associated with this transaction. If not given,
|
||||
|
@ -657,6 +657,7 @@ export interface PlanchetRecord {
|
||||
*/
|
||||
coinIdx: number;
|
||||
|
||||
|
||||
planchetStatus: PlanchetStatus;
|
||||
|
||||
lastError: TalerErrorDetail | undefined;
|
||||
@ -671,6 +672,12 @@ export interface PlanchetRecord {
|
||||
|
||||
coinEvHash: string;
|
||||
|
||||
/**
|
||||
* Index into the kappa-many planchet commitments per coin
|
||||
* for the age-withdraw operation.
|
||||
*/
|
||||
ageWithdrawIdx?: number;
|
||||
|
||||
ageCommitmentProof?: AgeCommitmentProof;
|
||||
}
|
||||
|
||||
@ -1423,7 +1430,7 @@ export interface KycPendingInfo {
|
||||
}
|
||||
/**
|
||||
* Group of withdrawal operations that need to be executed.
|
||||
* (Either for a normal withdrawal or from a reward.)
|
||||
* (Either for a normal {single-|batch-|age-} withdrawal or from a reward.)
|
||||
*
|
||||
* The withdrawal group record is only created after we know
|
||||
* the coin selection we want to withdraw.
|
||||
@ -2513,6 +2520,11 @@ export const WalletStoresV1 = {
|
||||
"planchets",
|
||||
describeContents<PlanchetRecord>({ keyPath: "coinPub" }),
|
||||
{
|
||||
byGroupAgeCoin: describeIndex("byGroupAgeCoin", [
|
||||
"withdrawalGroupId",
|
||||
"ageWithdrawIdx",
|
||||
"coinIdx",
|
||||
]),
|
||||
byGroupAndIndex: describeIndex("byGroupAndIndex", [
|
||||
"withdrawalGroupId",
|
||||
"coinIdx",
|
||||
|
@ -62,6 +62,10 @@ import {
|
||||
ExchangeWithdrawResponse,
|
||||
WithdrawUriInfoResponse,
|
||||
ExchangeBatchWithdrawRequest,
|
||||
ExchangeAgeWithdrawRequest,
|
||||
ExchangeAgeWithdrawRevealRequest,
|
||||
ExchangeAgeWithdrawResponse,
|
||||
ExchangeAgeWithdrawRevealResponse,
|
||||
TransactionState,
|
||||
TransactionMajorState,
|
||||
TransactionMinorState,
|
||||
@ -861,6 +865,7 @@ async function processPlanchetExchangeBatchRequest(
|
||||
coinIdx < wgContext.numPlanchets;
|
||||
coinIdx++
|
||||
) {
|
||||
// FIXME[oec]: Add lookup of planchet for age-withdraw here
|
||||
let planchet = await tx.planchets.indexes.byGroupAndIndex.get([
|
||||
withdrawalGroup.withdrawalGroupId,
|
||||
coinIdx,
|
||||
@ -923,6 +928,8 @@ async function processPlanchetExchangeBatchRequest(
|
||||
|
||||
// FIXME: handle individual error codes better!
|
||||
|
||||
// FIXME[oec]: add age-withdraw-request here
|
||||
|
||||
if (args.useBatchRequest) {
|
||||
const reqUrl = new URL(
|
||||
`reserves/${withdrawalGroup.reservePub}/batch-withdraw`,
|
||||
|
Loading…
Reference in New Issue
Block a user