wallet-core: age restriction crypto WIP

This commit is contained in:
Florian Dold 2022-04-18 21:23:37 +02:00
parent 68b4d0c4de
commit 2e0b9b9cff
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
4 changed files with 187 additions and 6 deletions

View File

@ -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;

View File

@ -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;
}

View File

@ -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 };

View File

@ -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")
}
}