gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-core] 01/03: initial commit for CS routines


From: gnunet
Subject: [taler-wallet-core] 01/03: initial commit for CS routines
Date: Thu, 03 Feb 2022 01:35:35 +0100

This is an automated email from the git hooks/post-receive script.

dold pushed a commit to branch master
in repository wallet-core.

commit 3b10e30ca14e6c18854fe16f750201f37289672b
Author: Gian Demarmels <gian@demarmels.org>
AuthorDate: Wed Jan 26 17:09:59 2022 +0100

    initial commit for CS routines
---
 packages/taler-util/package.json            |   4 +-
 packages/taler-util/src/talerCrypto.test.ts |  67 ++++++++++++
 packages/taler-util/src/talerCrypto.ts      | 155 ++++++++++++++++++++++++++++
 3 files changed, 225 insertions(+), 1 deletion(-)

diff --git a/packages/taler-util/package.json b/packages/taler-util/package.json
index 56b519de..694fbcc4 100644
--- a/packages/taler-util/package.json
+++ b/packages/taler-util/package.json
@@ -32,6 +32,7 @@
     "pretty": "prettier --write src"
   },
   "devDependencies": {
+    "@types/libsodium-wrappers-sumo": "^0.7.5",
     "@types/node": "^17.0.8",
     "ava": "^4.0.0",
     "esbuild": "^0.14.10",
@@ -42,6 +43,7 @@
   "dependencies": {
     "big-integer": "^1.6.51",
     "jed": "^1.1.1",
+    "libsodium-wrappers-sumo": "^0.7.9",
     "tslib": "^2.3.1"
   },
   "ava": {
@@ -49,4 +51,4 @@
       "lib/*test*"
     ]
   }
-}
\ No newline at end of file
+}
diff --git a/packages/taler-util/src/talerCrypto.test.ts 
b/packages/taler-util/src/talerCrypto.test.ts
index e9dfed4d..98de2a5a 100644
--- a/packages/taler-util/src/talerCrypto.test.ts
+++ b/packages/taler-util/src/talerCrypto.test.ts
@@ -27,6 +27,13 @@ import {
   keyExchangeEcdheEddsa,
   stringToBytes,
   bytesToString,
+  hash,
+  deriveBSeed,
+  csBlind,
+  calcS,
+  csUnblind,
+  csVerify,
+  CsSignature,
 } from "./talerCrypto.js";
 import { sha512, kdf } from "./kdf.js";
 import * as nacl from "./nacl-fast.js";
@@ -35,6 +42,7 @@ import { initNodePrng } from "./prng-node.js";
 // Since we import nacl-fast directly (and not via index.node.ts), we need to
 // init the PRNG manually.
 initNodePrng();
+import { AssertionError } from "assert";
 
 test("encoding", (t) => {
   const s = "Hello, World";
@@ -189,3 +197,62 @@ test("taler-exchange-tvg eddsa_ecdh #2", (t) => {
   );
   t.deepEqual(encodeCrock(myKm2), key_material);
 });
+
+test("taler CS blind c", async (t) => {
+  type CsBlindSignature = {
+    sBlind: Uint8Array;
+    rPubBlind: Uint8Array;
+  };
+  /**
+   * CS denomination keypair
+   */
+  const priv = "9TM70AKDTS57AWY9JK2J4TMBTMW6K62WHHGZWYDG0VM5ABPZKD40";
+  const pub = "8GSJZ649T2PXMKZC01Y4ANNBE7MF14QVK9SQEC4E46ZHKCVG8AS0";
+
+  /**
+   * rPub is returned from the exchange's new /csr API
+   */
+  const rPriv1 = "9TM70AKDTS57AWY9JK2J4TMBTMW6K62WHHGZWYDG0VM5ABPZKD41";
+  const rPriv2 = "8TM70AKDTS57AWY9JK2J4TMBTMW6K62WHHGZWYDG0VM5ABPZKD42";
+  const rPub1 = nacl.crypto_sign_keyPair_fromSeed(
+    decodeCrock(rPriv1),
+  ).publicKey;
+  const rPub2 = nacl.crypto_sign_keyPair_fromSeed(
+    decodeCrock(rPriv2),
+  ).publicKey;
+  const rPub:[Uint8Array,Uint8Array] = [rPub1, rPub2];
+
+  /**
+   * Coin key pair
+   */
+  const priv_eddsa = "1KG54M8T3X8BSFSZXCR3SQBSR7Y9P53NX61M864S7TEVMJ2XVPF0";
+  const pub_eddsa = eddsaGetPublic(decodeCrock(priv_eddsa));
+
+  const bseed = deriveBSeed(decodeCrock(priv_eddsa), [rPub1, rPub2]);
+
+  // Check that derivation is deterministic
+  const bseed2 = deriveBSeed(decodeCrock(priv_eddsa), [rPub1, rPub2]);
+  t.deepEqual(bseed, bseed2);
+
+  const coinPubHash = hash(pub_eddsa);
+
+  const c = await csBlind(bseed, [rPub1, rPub2], decodeCrock(pub), 
coinPubHash);
+
+  const b = Buffer.from(kdf(1, decodeCrock(priv), new Uint8Array(),new 
Uint8Array())).readUInt8() % 2;
+  if(b !=1 && b !=0){
+    throw new AssertionError();
+  }
+  const blindsig: CsBlindSignature ={
+    sBlind: await calcS(rPub[b],c[b],decodeCrock(priv)),
+    rPubBlind: rPub[b],
+  };
+  const sigblindsig: CsSignature = {
+    s: blindsig.sBlind,
+    rPub: blindsig.rPubBlind,
+  };
+
+  const sig = await csUnblind(bseed,rPub, decodeCrock(pub),b,blindsig);
+  
+  //const res = await csVerify(coinPubHash, sig, decodeCrock(pub));
+  t.deepEqual(res, true);
+});
diff --git a/packages/taler-util/src/talerCrypto.ts 
b/packages/taler-util/src/talerCrypto.ts
index 5f1c2e8c..27a3b314 100644
--- a/packages/taler-util/src/talerCrypto.ts
+++ b/packages/taler-util/src/talerCrypto.ts
@@ -24,7 +24,9 @@
 import * as nacl from "./nacl-fast.js";
 import { kdf } from "./kdf.js";
 import bigint from "big-integer";
+import sodium, { compare } from "libsodium-wrappers-sumo";
 import { DenominationPubKey, DenomKeyType } from "./talerTypes.js";
+import { AssertionError, equal } from "assert";
 
 export function getRandomBytes(n: number): Uint8Array {
   return nacl.randomBytes(n);
@@ -323,6 +325,159 @@ export function rsaVerify(
   return sig_e.equals(d);
 }
 
+export type CsSignature = {
+  s: Uint8Array;
+  rPub: Uint8Array;
+};
+
+export type CsBlindSignature = {
+  sBlind: Uint8Array;
+  rPubBlind: Uint8Array;
+};
+
+type BlindingSecrets = {
+  alpha: [Uint8Array,Uint8Array];
+  beta: [Uint8Array,Uint8Array];
+};
+
+//FIXME: Set correct salt
+function deriveSecrets(bseed: Uint8Array): BlindingSecrets {
+  const outLen = 128;
+  const salt = "94KPT83PCNS7J83KC5P78Y8";
+  const rndout = kdf(outLen, bseed, decodeCrock(salt));
+  const secrets: BlindingSecrets = {
+    alpha: [rndout.slice(0, 32), rndout.slice(32, 64)],
+    beta:  [rndout.slice(64, 96), rndout.slice(96, 128)],
+  };
+  return secrets;
+}
+
+function calcRDash(
+  csPub: Uint8Array,
+  secrets: BlindingSecrets,
+  rPub: [Uint8Array, Uint8Array],
+): [Uint8Array, Uint8Array] {
+  //const aG1 = nacl.scalarMult_base();
+  //const aG2 = nacl.scalarMult_base(secrets.alpha2);
+  //const bDp1 = nacl.scalarMult(secrets.beta1, csPub);
+  //const bDp2 = nacl.scalarMult(secrets.beta2, csPub);
+
+  const aG0 = sodium.crypto_scalarmult_ed25519_base_noclamp(secrets.alpha[0]);
+  const aG2 = sodium.crypto_scalarmult_ed25519_base_noclamp(secrets.alpha[1]);
+
+  const bDp0 = sodium.crypto_scalarmult_ed25519(secrets.beta[0], csPub);
+  const bDp1 = sodium.crypto_scalarmult_ed25519(secrets.beta[1], csPub);
+
+  const res0 = sodium.crypto_core_ed25519_add(aG0, bDp0);
+  const res2 = sodium.crypto_core_ed25519_add(aG2, bDp1);
+  return [
+    sodium.crypto_core_ed25519_add(rPub[0], res0),
+    sodium.crypto_core_ed25519_add(rPub[1], res2),
+  ];
+}
+
+//FIXME: How to pad two ikms correctly?
+//FIXME:_Is kdfMod used correctly?
+//FIXME: CDash1 is a JS Number array -> are they broken? how to convert bigint 
back to uint8arrays?
+function csFDH(
+  hm: Uint8Array,
+  rPub: Uint8Array,
+) : Uint8Array{
+  const lMod = Array.from(new Uint8Array([
+    0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2,
+    0xde, 0xf9, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+  ]));
+  const L = bigint.fromArray(lMod, 256, false);
+  const res = kdfMod(L, hm, rPub, rPub).toArray(256).value;
+  return new Uint8Array(res);
+}
+
+
+function deriveC(
+  hm: Uint8Array,
+  rPubDash: [Uint8Array, Uint8Array],
+): [Uint8Array, Uint8Array] {
+  const cDash1 = csFDH(hm,rPubDash[0]);
+  const cDash2 = csFDH(hm,rPubDash[1]);
+  return [cDash1, cDash2];
+}
+
+
+//FIXME: Set correct salt and do correct KDF
+// How to do this in one round with Uint8Array?
+// How to pad two ikms correctly?
+export function deriveBSeed(
+  coinPriv: Uint8Array,
+  rPub: [Uint8Array, Uint8Array],
+): Uint8Array {
+  const outLen = 32;
+  const salt = "94KPT83PCNS7J83KC5P78Y8";
+  const res = kdf(outLen, coinPriv, decodeCrock(salt), rPub[0]);
+  return kdf(outLen, res, decodeCrock(salt), rPub[1]);
+}
+
+export async function csBlind(
+  bseed: Uint8Array,
+  rPub: [Uint8Array, Uint8Array],
+  csPub: Uint8Array,
+  hm: Uint8Array,
+): Promise<[Uint8Array, Uint8Array]> {
+  await sodium.ready;
+  const secrets = deriveSecrets(bseed);
+  const rPubDash = calcRDash(csPub, secrets, rPub);
+  const c = deriveC(hm, rPubDash);
+  return [
+    sodium.crypto_core_ed25519_scalar_add(c[0], secrets.beta[0]),
+    sodium.crypto_core_ed25519_scalar_add(c[1], secrets.beta[1]),
+  ];
+}
+
+export async function calcS(
+  rPubB: Uint8Array,
+  cB: Uint8Array,
+  csPriv: Uint8Array,
+): Promise<Uint8Array> {
+  await sodium.ready;
+  const cBcsPriv = sodium.crypto_core_ed25519_scalar_mul(cB,csPriv);
+  return sodium.crypto_core_ed25519_scalar_add(rPubB,cBcsPriv);
+}
+
+//FIXME: Whats an int here??
+export async function csUnblind(
+  bseed: Uint8Array,
+  rPub: [Uint8Array, Uint8Array],
+  csPub: Uint8Array,
+  b: number,
+  csSig: CsBlindSignature,
+): Promise<CsSignature> {
+  
+  if(b != 0 && b !=1){
+    throw new AssertionError();
+  }
+  await sodium.ready;
+  const secrets = deriveSecrets(bseed);
+  const rPubDash = calcRDash(csPub, secrets, rPub)[b];
+  const sig :CsSignature = {
+    s: sodium.crypto_core_ed25519_scalar_add(csSig.sBlind, secrets.alpha[b]),
+    rPub: rPubDash,
+  };
+  return sig;
+}
+
+export async function csVerify(
+  hm: Uint8Array,
+  csSig: CsSignature,
+  csPub: Uint8Array,
+): Promise<boolean> {
+  await sodium.ready;
+  const cDash = csFDH(hm, csSig.rPub);
+  const sG = sodium.crypto_scalarmult_ed25519_base_noclamp(csSig.s);
+  const cbDp = sodium.crypto_scalarmult_ed25519_noclamp(cDash,csPub);
+  const sGeq = sodium.crypto_core_ed25519_add(csSig.rPub,cbDp);
+  return sodium.memcmp(sG,sGeq);
+}
+
 export interface EddsaKeyPair {
   eddsaPub: Uint8Array;
   eddsaPriv: Uint8Array;

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]