gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] 02/03: - added CS cryptographic routines


From: gnunet
Subject: [taler-wallet-core] 02/03: - added CS cryptographic routines
Date: Thu, 03 Feb 2022 01:35:36 +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 003ba5e91bb016caa1d068805723edc3e15f4d30
Author: Gian Demarmels <gian@demarmels.org>
AuthorDate: Thu Jan 27 14:42:33 2022 +0100

    - added CS cryptographic routines
---
 packages/taler-util/src/talerCrypto.test.ts | 163 +++++++++++++++----
 packages/taler-util/src/talerCrypto.ts      | 244 +++++++++++++++++++---------
 2 files changed, 298 insertions(+), 109 deletions(-)

diff --git a/packages/taler-util/src/talerCrypto.test.ts 
b/packages/taler-util/src/talerCrypto.test.ts
index 98de2a5a..35046359 100644
--- a/packages/taler-util/src/talerCrypto.test.ts
+++ b/packages/taler-util/src/talerCrypto.test.ts
@@ -27,13 +27,13 @@ import {
   keyExchangeEcdheEddsa,
   stringToBytes,
   bytesToString,
-  hash,
   deriveBSeed,
   csBlind,
-  calcS,
   csUnblind,
   csVerify,
-  CsSignature,
+  scalarMultBase25519,
+  deriveSecrets,
+  calcRBlind,
 } from "./talerCrypto.js";
 import { sha512, kdf } from "./kdf.js";
 import * as nacl from "./nacl-fast.js";
@@ -42,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 bigint from "big-integer";
 import { AssertionError } from "assert";
 
 test("encoding", (t) => {
@@ -199,6 +200,37 @@ test("taler-exchange-tvg eddsa_ecdh #2", (t) => {
 });
 
 test("taler CS blind c", async (t) => {
+  /**$
+   * Test Vectors:
+    {
+      "operation": "cs_blind_signing",
+      "message_hash": 
"KZ7540050MWFPPPJ6C0910TC15AWD6KN6GMK4YH8PY5Z2RKP7NQMHZ1NDD7JHD9CA2CZXDKYN7XRX521YERAF6N50VJZMHWPH18TCFG",
+      "cs_public_key": "1903SZ7QE1K8T4BHTJ32KDJ153SBXT22DGNQDY5NKJE535J72H2G",
+      "cs_private_key": "K43QAMEPE9KJJTX6AJZD6N4SN1N3ARVAXZ2MRNPT85FHD4QD2C60",
+      "cs_nonce": "GWPVFP9160XNADYQZ4T6S7RACB2482KG1JCY0X2Z5R52W74YXY3G",
+      "cs_r_priv_0": "B01FJCRCST8JM10K17SJXY7S7HH7T65JMFQ03H6PNYY9Z167Q1T0",
+      "cs_r_priv_1": "N3GW5X6VYSB8PY83CYNHJ3PN6TCA5N5BCS4WT2WEEQH7MTK915P0",
+      "cs_r_pub_0": "J5XFBKFP9T6BM02H6ZV6Y568PQ2K398MD339036F25XTSP1A7T3G",
+      "cs_r_pub_1": "GA2CZKJ6CWFS81ZN1T5R4GQFHF7XJV6HWHDR1JA9VATKKXQN89J0",
+      "cs_bs_alpha_0": "R06FWJ4XEK4JKKKA03JARGD0PD5JAX8DK2N6J0K8CAZZMVQEJ1T0",
+      "cs_bs_alpha_1": "13NXE2FEHJS0Q5XCWNRF4V1NC3BSAHN6BW02WZ07PG6967156HYG",
+      "cs_bs_beta_0": "T3EZP42RJQXRTJ4FTDWF18Z422VX7KFGN8GJ3QCCM1QV3N456HD0",
+      "cs_bs_beta_1": "P3MECYGCCR58QVEDSW443699CDXVT8C8W5ZT22PPNRJ363M72H6G",
+      "cs_r_pub_blind_0": 
"CHK7JC4SXZ4Y9RDA3881S82F7BP99H35Q361WR6RBXN5YN2ZM1M0",
+      "cs_r_pub_blind_1": 
"4C65R74GA9PPDX4DC2B948W96T3Z6QEENK2NDJQPNB9QBTKCT590",
+      "cs_c_0": "F288QXT67TR36E6DHE399G8J24RM6C3DP16HGMH74B6WZ1DETR10",
+      "cs_c_1": "EFK5WTN01NCVS3DZCG20MQDHRHBATRG8589BA0XSZDZ6D0HFR470",
+      "cs_blind_s": "6KZF904YZA8KK4C8X5JV57E7B84SR8TDDN9GDC8QTRRSNTHJTM4G",
+      "cs_b": "0000000",
+      "cs_sig_s": "F4ZKMFW3Q7DFN0N94KAMG2JFFHAC362T0QZ6ZCVZ73RS8P91CR70",
+      "cs_sig_R": "CHK7JC4SXZ4Y9RDA3881S82F7BP99H35Q361WR6RBXN5YN2ZM1M0",
+      "cs_c_blind_0": "6TN5454DZCHBDXFAGQFXQY37FNX6YRKW0MPFEX4TG5EHXC98M840",
+      "cs_c_blind_1": "EX6MYRZX6EC93YB4EE3M7AR3PQDYYG4092917YF29HD36X58NG0G",
+      "cs_prehash_0": 
"D29BBP762HEN6ZHZ5T2T6S4VMV400K9Y659M1QQZYZ0WJS3V3EJSF0FVXSCD1E99JJJMW295EY8TEE97YEGSGEQ0Q0A9DDMS2NCAG9R",
+      "cs_prehash_1": 
"9BYD02BC29ZF26BG88DWFCCENCS8CD8VZN76XP8JPWKTN9JS73MBCD0F36N0JSM223MRNJZACNYPMW23SGRHYVSP6BTT79GSSK5R228"
+    }
+   */
+
   type CsBlindSignature = {
     sBlind: Uint8Array;
     rPubBlind: Uint8Array;
@@ -206,53 +238,114 @@ test("taler CS blind c", async (t) => {
   /**
    * CS denomination keypair
    */
-  const priv = "9TM70AKDTS57AWY9JK2J4TMBTMW6K62WHHGZWYDG0VM5ABPZKD40";
-  const pub = "8GSJZ649T2PXMKZC01Y4ANNBE7MF14QVK9SQEC4E46ZHKCVG8AS0";
+  const priv = "K43QAMEPE9KJJTX6AJZD6N4SN1N3ARVAXZ2MRNPT85FHD4QD2C60";
+  const pub_cmp = "1903SZ7QE1K8T4BHTJ32KDJ153SBXT22DGNQDY5NKJE535J72H2G";
+  const pub = await scalarMultBase25519(decodeCrock(priv));
+  t.deepEqual(decodeCrock(pub_cmp), pub);
+
+  const nonce = "GWPVFP9160XNADYQZ4T6S7RACB2482KG1JCY0X2Z5R52W74YXY3G";
+  const msg_hash =
+    
"KZ7540050MWFPPPJ6C0910TC15AWD6KN6GMK4YH8PY5Z2RKP7NQMHZ1NDD7JHD9CA2CZXDKYN7XRX521YERAF6N50VJZMHWPH18TCFG";
 
   /**
    * 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];
+  const rPriv0 = "B01FJCRCST8JM10K17SJXY7S7HH7T65JMFQ03H6PNYY9Z167Q1T0";
+  const rPriv1 = "N3GW5X6VYSB8PY83CYNHJ3PN6TCA5N5BCS4WT2WEEQH7MTK915P0";
+  const rPub0 = await scalarMultBase25519(decodeCrock(rPriv0));
+  const rPub1 = await scalarMultBase25519(decodeCrock(rPriv1));
+
+  const rPub: [Uint8Array, Uint8Array] = [rPub0, rPub1];
+
+  t.deepEqual(
+    rPub[0],
+    decodeCrock("J5XFBKFP9T6BM02H6ZV6Y568PQ2K398MD339036F25XTSP1A7T3G"),
+  );
+  t.deepEqual(
+    rPub[1],
+    decodeCrock("GA2CZKJ6CWFS81ZN1T5R4GQFHF7XJV6HWHDR1JA9VATKKXQN89J0"),
+  );
 
   /**
-   * Coin key pair
+   * Test if blinding seed derivation is deterministic
+   * In the wallet the b-seed MUST be different from the Withdraw-Nonce or 
Refresh Nonce!
+   * (Eg. derive two different values from coin priv) -> See CS protocols for 
details
    */
   const priv_eddsa = "1KG54M8T3X8BSFSZXCR3SQBSR7Y9P53NX61M864S7TEVMJ2XVPF0";
-  const pub_eddsa = eddsaGetPublic(decodeCrock(priv_eddsa));
+  // const pub_eddsa = eddsaGetPublic(decodeCrock(priv_eddsa));
+  const bseed1 = deriveBSeed(decodeCrock(priv_eddsa), rPub);
+  const bseed2 = deriveBSeed(decodeCrock(priv_eddsa), rPub);
+  t.deepEqual(bseed1, bseed2);
 
-  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);
+  /**
+   * In this scenario the nonce from the test vectors is used as b-seed and 
refresh.
+   * This is only used in testing to test functionality.
+   * DO NOT USE the same values for blinding-seed and nonce anywhere else.
+   *
+   * Tests whether the blinding secrets are derived as in the exchange 
implementation
+   */
+  const bseed = decodeCrock(nonce);
+  const secrets = deriveSecrets(bseed);
+  t.deepEqual(
+    secrets.alpha[0],
+    decodeCrock("R06FWJ4XEK4JKKKA03JARGD0PD5JAX8DK2N6J0K8CAZZMVQEJ1T0"),
+  );
+  t.deepEqual(
+    secrets.alpha[1],
+    decodeCrock("13NXE2FEHJS0Q5XCWNRF4V1NC3BSAHN6BW02WZ07PG6967156HYG"),
+  );
+  t.deepEqual(
+    secrets.beta[0],
+    decodeCrock("T3EZP42RJQXRTJ4FTDWF18Z422VX7KFGN8GJ3QCCM1QV3N456HD0"),
+  );
+  t.deepEqual(
+    secrets.beta[1],
+    decodeCrock("P3MECYGCCR58QVEDSW443699CDXVT8C8W5ZT22PPNRJ363M72H6G"),
+  );
 
-  const coinPubHash = hash(pub_eddsa);
+  const rBlind = calcRBlind(pub, secrets, rPub);
+  t.deepEqual(
+    rBlind[0],
+    decodeCrock("CHK7JC4SXZ4Y9RDA3881S82F7BP99H35Q361WR6RBXN5YN2ZM1M0"),
+  );
+  t.deepEqual(
+    rBlind[1],
+    decodeCrock("4C65R74GA9PPDX4DC2B948W96T3Z6QEENK2NDJQPNB9QBTKCT590"),
+  );
 
-  const c = await csBlind(bseed, [rPub1, rPub2], decodeCrock(pub), 
coinPubHash);
+  const c = await csBlind(bseed, rPub, pub, decodeCrock(msg_hash));
+  t.deepEqual(
+    c[0],
+    decodeCrock("F288QXT67TR36E6DHE399G8J24RM6C3DP16HGMH74B6WZ1DETR10"),
+  );
+  t.deepEqual(
+    c[1],
+    decodeCrock("EFK5WTN01NCVS3DZCG20MQDHRHBATRG8589BA0XSZDZ6D0HFR470"),
+  );
 
-  const b = Buffer.from(kdf(1, decodeCrock(priv), new Uint8Array(),new 
Uint8Array())).readUInt8() % 2;
-  if(b !=1 && b !=0){
-    throw new AssertionError();
+  const lMod = Array.from(
+    new Uint8Array([
+      0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x14, 0xde, 0xf9, 0xde, 0xa2, 0xf7, 0x9c, 0xd6,
+      0x58, 0x12, 0x63, 0x1a, 0x5c, 0xf5, 0xd3, 0xed,
+    ]),
+  );
+  const L = bigint.fromArray(lMod, 256, false).toString();
+  //Lmod needs to be 2^252+27742317777372353535851937790883648493
+  if (!L.startsWith("723700")) {
+    throw new AssertionError({ message: L });
   }
-  const blindsig: CsBlindSignature ={
-    sBlind: await calcS(rPub[b],c[b],decodeCrock(priv)),
+
+  const b = 0;
+  const blindsig: CsBlindSignature = {
+    sBlind: 
decodeCrock("6KZF904YZA8KK4C8X5JV57E7B84SR8TDDN9GDC8QTRRSNTHJTM4G"),
     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));
+  const sig = await csUnblind(bseed, rPub, pub, b, blindsig);
+  t.deepEqual(sig.s, 
decodeCrock("F4ZKMFW3Q7DFN0N94KAMG2JFFHAC362T0QZ6ZCVZ73RS8P91CR70"));
+  t.deepEqual(sig.rPub, 
decodeCrock("CHK7JC4SXZ4Y9RDA3881S82F7BP99H35Q361WR6RBXN5YN2ZM1M0"));
+
+  const res = await csVerify(decodeCrock(msg_hash), sig, pub);
   t.deepEqual(res, true);
 });
diff --git a/packages/taler-util/src/talerCrypto.ts 
b/packages/taler-util/src/talerCrypto.ts
index 27a3b314..934a04e8 100644
--- a/packages/taler-util/src/talerCrypto.ts
+++ b/packages/taler-util/src/talerCrypto.ts
@@ -24,7 +24,7 @@
 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 sodium from "libsodium-wrappers-sumo";
 import { DenominationPubKey, DenomKeyType } from "./talerTypes.js";
 import { AssertionError, equal } from "assert";
 
@@ -193,6 +193,32 @@ function kdfMod(
   }
 }
 
+function csKdfMod(
+  n: bigint.BigInteger,
+  ikm: Uint8Array,
+  salt: Uint8Array,
+  info: Uint8Array,
+): Uint8Array {
+  const nbits = n.bitLength().toJSNumber();
+  const buflen = Math.floor((nbits - 1) / 8 + 1);
+  const mask = (1 << (8 - (buflen * 8 - nbits))) - 1;
+  let counter = 0;
+  while (true) {
+    const ctx = new Uint8Array(info.byteLength + 2);
+    ctx.set(info, 0);
+    ctx[ctx.length - 2] = (counter >>> 8) & 0xff;
+    ctx[ctx.length - 1] = counter & 0xff;
+    const buf = kdf(buflen, ikm, salt, ctx);
+    const arr = Array.from(buf);
+    arr[0] = arr[0] & mask;
+    const r = bigint.fromArray(arr, 256, false);
+    if (r.lt(n)) {
+      return new Uint8Array(arr);
+    }
+    counter++;
+  }
+}
+
 // Newer versions of node have TextEncoder and TextDecoder as a global,
 // just like modern browsers.
 // In older versions of node or environments that do not have these
@@ -335,88 +361,153 @@ export type CsBlindSignature = {
   rPubBlind: Uint8Array;
 };
 
-type BlindingSecrets = {
-  alpha: [Uint8Array,Uint8Array];
-  beta: [Uint8Array,Uint8Array];
+export type CsBlindingSecrets = {
+  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)],
+function typedArrayConcat(chunks: Uint8Array[]): Uint8Array {
+  let payloadLen = 0;
+  for (const c of chunks) {
+    payloadLen += c.byteLength;
+  }
+  const buf = new ArrayBuffer(payloadLen);
+  const u8buf = new Uint8Array(buf);
+  let p = 0;
+  for (const c of chunks) {
+    u8buf.set(c, p);
+    p += c.byteLength;
+  }
+  return u8buf;
+}
+
+/**
+ * Map to scalar subgroup function
+ * perform clamping as described in RFC7748
+ * @param scalar
+ */
+function mtoSS(scalar: Uint8Array): Uint8Array {
+  scalar[0] &= 248;
+  scalar[31] &= 127;
+  scalar[31] |= 64;
+  return scalar;
+}
+
+/**
+ * The function returns the CS blinding secrets from a seed
+ * @param bseed seed to derive blinding secrets
+ * @returns blinding secrets
+ */
+export function deriveSecrets(bseed: Uint8Array): CsBlindingSecrets {
+  const outLen = 130;
+  const salt = stringToBytes("alphabeta");
+  const rndout = kdf(outLen, bseed, salt);
+  const secrets: CsBlindingSecrets = {
+    alpha: [mtoSS(rndout.slice(0, 32)), mtoSS(rndout.slice(64, 96))],
+    beta: [mtoSS(rndout.slice(32, 64)), mtoSS(rndout.slice(96, 128))],
   };
   return secrets;
 }
 
-function calcRDash(
+/**
+ * Used for testing, simple scalar multiplication with base point of Cuve25519
+ * @param s scalar
+ * @returns new point sG
+ */
+export async function scalarMultBase25519(s: Uint8Array): Promise<Uint8Array> {
+  await sodium.ready;
+  return sodium.crypto_scalarmult_ed25519_base_noclamp(s);
+}
+
+/**
+ * calculation of the blinded public point R in CS
+ * @param csPub denomination publik key
+ * @param secrets client blinding secrets
+ * @param rPub public R received from /csr API
+ */
+export function calcRBlind(
   csPub: Uint8Array,
-  secrets: BlindingSecrets,
+  secrets: CsBlindingSecrets,
   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 aG1 = 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 bDp0 = sodium.crypto_scalarmult_ed25519_noclamp(secrets.beta[0], 
csPub);
+  const bDp1 = sodium.crypto_scalarmult_ed25519_noclamp(secrets.beta[1], 
csPub);
 
   const res0 = sodium.crypto_core_ed25519_add(aG0, bDp0);
-  const res2 = sodium.crypto_core_ed25519_add(aG2, bDp1);
+  const res1 = sodium.crypto_core_ed25519_add(aG1, bDp1);
   return [
     sodium.crypto_core_ed25519_add(rPub[0], res0),
-    sodium.crypto_core_ed25519_add(rPub[1], res2),
+    sodium.crypto_core_ed25519_add(rPub[1], res1),
   ];
 }
 
-//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?
+/**
+ * FDH function used in CS
+ * @param hm message hash
+ * @param rPub public R included in FDH
+ * @param csPub denomination public key as context
+ * @returns mapped Curve25519 scalar
+ */
 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,
-  ]));
+  csPub: Uint8Array,
+): Uint8Array {
+  const lMod = Array.from(
+    new Uint8Array([
+      0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x14, 0xde, 0xf9, 0xde, 0xa2, 0xf7, 0x9c, 0xd6,
+      0x58, 0x12, 0x63, 0x1a, 0x5c, 0xf5, 0xd3, 0xed,
+    ]),
+  );
   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];
+  const info = stringToBytes("Curve25519FDH");
+  const preshash = sodium.crypto_hash_sha512(typedArrayConcat([rPub, hm]));
+  return csKdfMod(L, preshash, csPub, info).reverse();
 }
 
-
-//FIXME: Set correct salt and do correct KDF
-// How to do this in one round with Uint8Array?
-// How to pad two ikms correctly?
+/**
+ * blinding seed derived from coin private key
+ * @param coinPriv private key of the corresponding coin
+ * @param rPub public R received from /csr API
+ * @returns blinding seed
+ */
 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]);
+  const salt = stringToBytes("b-seed");
+  const ikm = typedArrayConcat([coinPriv, rPub[0], rPub[1]]);
+  return kdf(outLen, ikm, salt);
 }
 
+/**
+ * Derive withdraw nonce, used in /csr request
+ * Note: In withdraw protocol, the nonce is chosen randomly
+ * @param coinPriv coin private key
+ * @returns nonce
+ */
+export function deriveWithdrawNonce(
+  coinPriv: Uint8Array,
+): Uint8Array { 
+  const outLen = 32;
+  const salt = stringToBytes("n");
+  return kdf(outLen, coinPriv, salt);
+}
+
+/**
+ * Blind operation for CS signatures, used after /csr call
+ * @param bseed blinding seed to derive blinding secrets
+ * @param rPub public R received from /csr
+ * @param csPub denomination public key
+ * @param hm message to blind
+ * @returns two blinded c
+ */
 export async function csBlind(
   bseed: Uint8Array,
   rPub: [Uint8Array, Uint8Array],
@@ -425,25 +516,24 @@ export async function csBlind(
 ): Promise<[Uint8Array, Uint8Array]> {
   await sodium.ready;
   const secrets = deriveSecrets(bseed);
-  const rPubDash = calcRDash(csPub, secrets, rPub);
-  const c = deriveC(hm, rPubDash);
+  const rPubBlind = calcRBlind(csPub, secrets, rPub);
+  const c_0 = csFDH(hm, rPubBlind[0], csPub);
+  const c_1 = csFDH(hm, rPubBlind[1], csPub);
   return [
-    sodium.crypto_core_ed25519_scalar_add(c[0], secrets.beta[0]),
-    sodium.crypto_core_ed25519_scalar_add(c[1], secrets.beta[1]),
+    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??
+/**
+ * Unblind operation to unblind the signature
+ * @param bseed seed to derive secrets
+ * @param rPub public R received from /csr
+ * @param csPub denomination publick key
+ * @param b returned from exchange to select c
+ * @param csSig blinded signature
+ * @returns unblinded signature
+ */
 export async function csUnblind(
   bseed: Uint8Array,
   rPub: [Uint8Array, Uint8Array],
@@ -451,31 +541,37 @@ export async function csUnblind(
   b: number,
   csSig: CsBlindSignature,
 ): Promise<CsSignature> {
-  
-  if(b != 0 && b !=1){
+  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 = {
+  const rPubDash = calcRBlind(csPub, secrets, rPub)[b];
+  const sig: CsSignature = {
     s: sodium.crypto_core_ed25519_scalar_add(csSig.sBlind, secrets.alpha[b]),
     rPub: rPubDash,
   };
   return sig;
 }
 
+/**
+ * Verification algorithm for CS signatures
+ * @param hm message signed
+ * @param csSig unblinded signature
+ * @param csPub denomination publick key
+ * @returns true if valid, false if unvalid
+ */
 export async function csVerify(
   hm: Uint8Array,
   csSig: CsSignature,
   csPub: Uint8Array,
 ): Promise<boolean> {
   await sodium.ready;
-  const cDash = csFDH(hm, csSig.rPub);
+  const cDash = csFDH(hm, csSig.rPub, csPub);
   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);
+  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 {

-- 
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]