aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2022-04-18 21:23:37 +0200
committerFlorian Dold <florian@dold.me>2022-04-18 21:23:49 +0200
commit2e0b9b9cff43968a16eb9555cb6e128c979a604b (patch)
tree038e66c078e2a64acecfeff2f2c80d4128bfa35e
parent68b4d0c4de7df98190fcc07c11fa809622b27bfc (diff)
wallet-core: age restriction crypto WIP
-rw-r--r--packages/anastasis-core/src/crypto.ts1
-rw-r--r--packages/taler-util/src/nacl-fast.ts84
-rw-r--r--packages/taler-util/src/payto.ts10
-rw-r--r--packages/taler-util/src/talerCrypto.ts98
4 files changed, 187 insertions, 6 deletions
diff --git a/packages/anastasis-core/src/crypto.ts b/packages/anastasis-core/src/crypto.ts
index 9f412c6dc..815f84c11 100644
--- a/packages/anastasis-core/src/crypto.ts
+++ b/packages/anastasis-core/src/crypto.ts
@@ -32,6 +32,7 @@ import { argon2id } from "hash-wasm";
export type Flavor<T, FlavorT extends string> = T & {
_flavor?: `anastasis.${FlavorT}`;
};
+
export type FlavorP<T, FlavorT extends string, S extends number> = T & {
_flavor?: `anastasis.${FlavorT}`;
_size?: S;
diff --git a/packages/taler-util/src/nacl-fast.ts b/packages/taler-util/src/nacl-fast.ts
index 809a1a489..82bdc7cec 100644
--- a/packages/taler-util/src/nacl-fast.ts
+++ b/packages/taler-util/src/nacl-fast.ts
@@ -2564,7 +2564,7 @@ function crypto_sign_keypair(
return 0;
}
-const L = new Float64Array([
+export const L = new Float64Array([
0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde,
0xf9, 0xde, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10,
]);
@@ -3045,3 +3045,85 @@ export function crypto_core_ed25519_scalar_sub(
modL(o, z);
return o;
}
+
+export function crypto_edx25519_private_key_create(): Uint8Array {
+ const seed = new Uint8Array(32);
+ randombytes(seed, 32);
+ return crypto_edx25519_private_key_create_from_seed(seed);
+}
+
+export function crypto_edx25519_private_key_create_from_seed(
+ seed: Uint8Array,
+): Uint8Array {
+ const pk = hash(seed);
+ pk[0] &= 248;
+ pk[31] &= 127;
+ pk[31] |= 64;
+ return pk;
+}
+
+export function crypto_edx25519_get_public(priv: Uint8Array): Uint8Array {
+ const pub = new Uint8Array(32);
+ if (0 != crypto_scalarmult_base_noclamp(pub.subarray(32), priv)) {
+ throw Error();
+ }
+ return pub;
+}
+
+export function crypto_edx25519_sign_detached(
+ m: Uint8Array,
+ skx: Uint8Array,
+ pkx: Uint8Array,
+): Uint8Array {
+ const n: number = m.length;
+ const d = new Uint8Array(64),
+ h = new Uint8Array(64),
+ r = new Uint8Array(64);
+ let i, j;
+ const x = new Float64Array(64);
+ const p = [gf(), gf(), gf(), gf()];
+
+ for (i = 0; i < 64; i++) d[i] = skx[i];
+
+ const sm = new Uint8Array(n + 64);
+
+ for (i = 0; i < n; i++) sm[64 + i] = m[i];
+ for (i = 0; i < 32; i++) sm[32 + i] = d[32 + i];
+
+ crypto_hash(r, sm.subarray(32), n + 32);
+ reduce(r);
+ scalarbase(p, r);
+ pack(sm, p);
+
+ for (i = 32; i < 64; i++) sm[i] = pkx[i - 32];
+ crypto_hash(h, sm, n + 64);
+ reduce(h);
+
+ for (i = 0; i < 64; i++) x[i] = 0;
+ for (i = 0; i < 32; i++) x[i] = r[i];
+ for (i = 0; i < 32; i++) {
+ for (j = 0; j < 32; j++) {
+ x[i + j] += h[i] * d[j];
+ }
+ }
+
+ modL(sm.subarray(32), x);
+ return sm.subarray(64);
+}
+
+export function crypto_edx25519_sign_detached_verify(
+ msg: Uint8Array,
+ sig: Uint8Array,
+ publicKey: Uint8Array,
+): boolean {
+ checkArrayTypes(msg, sig, publicKey);
+ if (sig.length !== crypto_sign_BYTES) throw new Error("bad signature size");
+ if (publicKey.length !== crypto_sign_PUBLICKEYBYTES)
+ throw new Error("bad public key size");
+ const sm = new Uint8Array(crypto_sign_BYTES + msg.length);
+ const m = new Uint8Array(crypto_sign_BYTES + msg.length);
+ let i;
+ for (i = 0; i < crypto_sign_BYTES; i++) sm[i] = sig[i];
+ for (i = 0; i < msg.length; i++) sm[i + crypto_sign_BYTES] = msg[i];
+ return crypto_sign_open(m, sm, sm.length, publicKey) >= 0;
+}
diff --git a/packages/taler-util/src/payto.ts b/packages/taler-util/src/payto.ts
index 09d6856ca..dd764e42d 100644
--- a/packages/taler-util/src/payto.ts
+++ b/packages/taler-util/src/payto.ts
@@ -23,30 +23,30 @@ export type PaytoUri =
| PaytoUriTalerBank
| PaytoUriBitcoin;
-interface PaytoUriGeneric {
+export interface PaytoUriGeneric {
targetType: string;
targetPath: string;
params: { [name: string]: string };
}
-interface PaytoUriUnknown extends PaytoUriGeneric {
+export interface PaytoUriUnknown extends PaytoUriGeneric {
isKnown: false;
}
-interface PaytoUriIBAN extends PaytoUriGeneric {
+export interface PaytoUriIBAN extends PaytoUriGeneric {
isKnown: true;
targetType: "iban";
iban: string;
}
-interface PaytoUriTalerBank extends PaytoUriGeneric {
+export interface PaytoUriTalerBank extends PaytoUriGeneric {
isKnown: true;
targetType: "x-taler-bank";
host: string;
account: string;
}
-interface PaytoUriBitcoin extends PaytoUriGeneric {
+export interface PaytoUriBitcoin extends PaytoUriGeneric {
isKnown: true;
targetType: "bitcoin";
generateSegwitAddress: (r: string) => { addr1: string; addr2: string };
diff --git a/packages/taler-util/src/talerCrypto.ts b/packages/taler-util/src/talerCrypto.ts
index 6bcb592e3..282d22d8b 100644
--- a/packages/taler-util/src/talerCrypto.ts
+++ b/packages/taler-util/src/talerCrypto.ts
@@ -583,6 +583,11 @@ export interface EcdheKeyPair {
ecdhePriv: Uint8Array;
}
+export interface Edx25519Keypair {
+ edxPub: string;
+ edxPriv: string;
+}
+
export function createEddsaKeyPair(): EddsaKeyPair {
const eddsaPriv = nacl.randomBytes(32);
const eddsaPub = eddsaGetPublic(eddsaPriv);
@@ -787,3 +792,96 @@ export class SignaturePurposeBuilder {
export function buildSigPS(purposeNum: number): SignaturePurposeBuilder {
return new SignaturePurposeBuilder(purposeNum);
}
+
+export type Flavor<T, FlavorT extends string> = T & {
+ _flavor?: `taler.${FlavorT}`;
+};
+
+export type FlavorP<T, FlavorT extends string, S extends number> = T & {
+ _flavor?: `taler.${FlavorT}`;
+ _size?: S;
+};
+
+export type OpaqueData = Flavor<string, "OpaqueData">;
+export type Edx25519PublicKey = FlavorP<string, "Edx25519PublicKey", 32>;
+export type Edx25519PrivateKey = FlavorP<string, "Edx25519PrivateKey", 64>;
+export type Edx25519Signature = FlavorP<string, "Edx25519Signature", 64>;
+
+export namespace Edx25519 {
+ const revL = [
+ 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2,
+ 0xde, 0xf9, 0xde, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10,
+ ];
+
+ const L = bigint.fromArray(revL.reverse(), 256, false);
+
+ export async function keyCreateFromSeed(
+ seed: OpaqueData,
+ ): Promise<Edx25519PrivateKey> {
+ return encodeCrock(
+ nacl.crypto_edx25519_private_key_create_from_seed(decodeCrock(seed)),
+ );
+ }
+
+ export async function keyCreate(): Promise<Edx25519PrivateKey> {
+ return encodeCrock(nacl.crypto_edx25519_private_key_create());
+ }
+
+ export async function getPublic(
+ priv: Edx25519PrivateKey,
+ ): Promise<Edx25519PublicKey> {
+ return encodeCrock(nacl.crypto_edx25519_get_public(decodeCrock(priv)));
+ }
+
+ export function sign(
+ msg: OpaqueData,
+ key: Edx25519PrivateKey,
+ ): Promise<Edx25519Signature> {
+ throw Error("not implemented");
+ }
+
+ async function deriveFactor(
+ pub: Edx25519PublicKey,
+ seed: OpaqueData,
+ ): Promise<OpaqueData> {
+ const res = kdfKw({
+ outputLength: 64,
+ salt: stringToBytes("edx2559-derivation"),
+ ikm: decodeCrock(pub),
+ info: decodeCrock(seed),
+ });
+
+ return encodeCrock(res);
+ }
+
+ export async function privateKeyDerive(
+ priv: Edx25519PrivateKey,
+ seed: OpaqueData,
+ ): Promise<Edx25519PrivateKey> {
+ const pub = await getPublic(priv);
+ const privDec = decodeCrock(priv);
+ const privA = privDec.subarray(0, 32).reverse();
+ const a = bigint.fromArray(Array.from(privA), 256, false);
+
+ const factorBuf = await deriveFactor(pub, seed);
+
+ const factor = bigint.fromArray(Array.from(factorBuf), 256, false);
+
+ const aPrime = a.divide(8).multiply(factor).multiply(8);
+
+ const bPrime = nacl.hash(
+ typedArrayConcat([privDec.subarray(32, 64), decodeCrock(factorBuf)]),
+ );
+
+ Uint8Array.from(aPrime.toArray(256).value)
+
+ throw Error("not implemented");
+ }
+
+ export function publicKeyDerive(
+ priv: Edx25519PrivateKey,
+ seed: OpaqueData,
+ ): Promise<Edx25519PublicKey> {
+ throw Error("not implemented")
+ }
+}