Skip to content

Commit

Permalink
add tests to check creating invoice and invoice payments
Browse files Browse the repository at this point in the history
  • Loading branch information
lukachi committed Dec 30, 2024
1 parent 1638fad commit b7e664d
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 436 deletions.
71 changes: 31 additions & 40 deletions src/core/crypto/veiled/VeiledInvoice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import { bytesToNumberLE, concatBytes, numberToBytesLE } from "@noble/curves/abs
import { RistrettoPoint } from "@noble/curves/ed25519";
import { utf8ToBytes } from "@noble/hashes/utils";
import { H_RISTRETTO, TwistedEd25519PrivateKey, TwistedEd25519PublicKey } from "../twistedEd25519";
import { TwistedElGamal, TwistedElGamalCiphertext } from "../twistedElGamal";
import { TwistedElGamalCiphertext } from "../twistedElGamal";
import { ed25519GenListOfRandom, ed25519modN } from "../utils";
import { PROOF_CHUNK_SIZE, SIGMA_PROOF_TRANSFER_SIZE } from "./consts";
import { genFiatShamirChallenge, publicKeyToU8 } from "./helpers";
import { genFiatShamirChallenge } from "./helpers";
import { RangeProofExecutor } from "../rangeProof";
import { VeiledAmount } from "./veiledAmount";

Expand All @@ -18,39 +18,30 @@ export type VeiledInvoiceSigmaProof = {
};

export type CreateVeiledInvoiceOpArgs = {
senderDecryptionKey: TwistedEd25519PrivateKey;
creatorDecryptionKey: TwistedEd25519PrivateKey;
payerPublicKey: TwistedEd25519PublicKey;
invoiceValueAmount: bigint;
encryptedInvoiceValue: TwistedElGamalCiphertext[];
auditorEncryptionKeys?: TwistedEd25519PublicKey[];
randomness?: bigint[];
};

export class VeiledInvoice {
senderDecryptionKey: TwistedEd25519PrivateKey;
creatorDecryptionKey: TwistedEd25519PrivateKey;

veiledInvoiceValue: VeiledAmount;

auditorEncryptionKeys: TwistedEd25519PublicKey[];

auditorsU8EncryptionKeys: Uint8Array[];
payerPublicKey: TwistedEd25519PublicKey;

auditorsVBList: TwistedElGamalCiphertext[][];
veiledInvoiceValue: VeiledAmount;

randomness: bigint[];

constructor(args: {
senderDecryptionKey: TwistedEd25519PrivateKey;
creatorDecryptionKey: TwistedEd25519PrivateKey;
payerPublicKey: TwistedEd25519PublicKey;
veiledInvoiceValue: VeiledAmount;
auditorEncryptionKeys: TwistedEd25519PublicKey[];
auditorsU8EncryptionKeys: Uint8Array[];
auditorsVBList: TwistedElGamalCiphertext[][];
randomness: bigint[];
}) {
this.senderDecryptionKey = args.senderDecryptionKey;
this.creatorDecryptionKey = args.creatorDecryptionKey;
this.payerPublicKey = args.payerPublicKey;
this.veiledInvoiceValue = args.veiledInvoiceValue;
this.auditorEncryptionKeys = args.auditorEncryptionKeys;
this.auditorsU8EncryptionKeys = args.auditorsU8EncryptionKeys;
this.auditorsVBList = args.auditorsVBList;
this.randomness = args.randomness;
}

Expand All @@ -60,21 +51,12 @@ export class VeiledInvoice {
const veiledInvoiceValue = VeiledAmount.fromAmount(args.invoiceValueAmount, {
chunksCount: 2,
});
veiledInvoiceValue.encrypt(args.senderDecryptionKey.publicKey(), randomness);

const auditorsU8PublicKeys = args.auditorEncryptionKeys?.map((pk) => publicKeyToU8(pk)) ?? [];

const auditorsVBList =
args.auditorEncryptionKeys?.map((el) =>
veiledInvoiceValue.amountChunks.map((chunk, i) => TwistedElGamal.encryptWithPK(chunk, el, randomness[i])),
) || [];
veiledInvoiceValue.encrypt(args.payerPublicKey, randomness);

return new VeiledInvoice({
senderDecryptionKey: args.senderDecryptionKey,
creatorDecryptionKey: args.creatorDecryptionKey,
payerPublicKey: args.payerPublicKey,
veiledInvoiceValue,
auditorEncryptionKeys: args.auditorEncryptionKeys ?? [],
auditorsU8EncryptionKeys: auditorsU8PublicKeys,
auditorsVBList,
randomness,
});
}
Expand Down Expand Up @@ -119,10 +101,10 @@ export class VeiledInvoice {
}

async genSigmaProof(): Promise<VeiledInvoiceSigmaProof> {
if (this.randomness && this.randomness.length !== VeiledAmount.CHUNKS_COUNT)
if (this.randomness && this.randomness.length !== this.veiledInvoiceValue.chunksCount)
throw new TypeError("Invalid length list of randomness");

const senderPKRistretto = RistrettoPoint.fromHex(this.senderDecryptionKey.publicKey().toUint8Array());
const senderPKRistretto = RistrettoPoint.fromHex(this.payerPublicKey.toUint8Array());

// Prover selects random x1j[], x2j[], where j in {0, 1}
const j = 2;
Expand All @@ -140,7 +122,7 @@ export class VeiledInvoice {
utf8ToBytes(VeiledInvoice.FIAT_SHAMIR_SIGMA_DST),
RistrettoPoint.BASE.toRawBytes(),
H_RISTRETTO.toRawBytes(),
this.senderDecryptionKey.publicKey().toUint8Array(),
this.payerPublicKey.toUint8Array(),
...this.veiledInvoiceValue.amountEncrypted!.map((el) => el.serialize()).flat(),
...X1List.map((el) => el.toRawBytes()),
...X2List.map((el) => el.toRawBytes()),
Expand All @@ -160,8 +142,7 @@ export class VeiledInvoice {
}

static verifySigmaProof(opts: {
senderPublicKey: TwistedEd25519PublicKey;
recipientPublicKey: TwistedEd25519PublicKey;
payerPublicKey: TwistedEd25519PublicKey;
encryptedInvoiceAmount: TwistedElGamalCiphertext[];
sigmaProof: VeiledInvoiceSigmaProof;
}): boolean {
Expand All @@ -172,7 +153,7 @@ export class VeiledInvoice {
utf8ToBytes(VeiledInvoice.FIAT_SHAMIR_SIGMA_DST),
RistrettoPoint.BASE.toRawBytes(),
H_RISTRETTO.toRawBytes(),
opts.senderPublicKey.toUint8Array(),
opts.payerPublicKey.toUint8Array(),
...opts.encryptedInvoiceAmount.map((el) => el.serialize()).flat(),
...opts.sigmaProof.X1List,
...opts.sigmaProof.X2List,
Expand All @@ -188,12 +169,22 @@ export class VeiledInvoice {
.add(opts.encryptedInvoiceAmount[idx].C.multiply(p)),
);

const senderPKRistretto = RistrettoPoint.fromHex(opts.senderPublicKey.toString());
const senderPKRistretto = RistrettoPoint.fromHex(opts.payerPublicKey.toUint8Array());

const X2List = alpha2LEList
.slice(0, j)
.map((el, idx) => senderPKRistretto.multiply(el).add(opts.encryptedInvoiceAmount[idx].D.multiply(p)));

console.log(
"X1List",
X1List.every((X1, i) => X1.equals(RistrettoPoint.fromHex(opts.sigmaProof.X1List[i]))),
);

console.log(
"X2List",
X2List.every((X2, i) => X2.equals(RistrettoPoint.fromHex(opts.sigmaProof.X2List[i]))),
);

return (
X1List.every((X1, i) => X1.equals(RistrettoPoint.fromHex(opts.sigmaProof.X1List[i]))) &&
X2List.every((X2, i) => X2.equals(RistrettoPoint.fromHex(opts.sigmaProof.X2List[i])))
Expand All @@ -205,7 +196,7 @@ export class VeiledInvoice {
this.veiledInvoiceValue.amountChunks.map((chunk) =>
RangeProofExecutor.generateRangeZKP({
v: chunk,
r: this.senderDecryptionKey.toUint8Array(),
r: this.creatorDecryptionKey.toUint8Array(),
valBase: RistrettoPoint.BASE.toRawBytes(),
randBase: H_RISTRETTO.toRawBytes(),
}),
Expand Down
21 changes: 18 additions & 3 deletions src/core/crypto/veiled/veiledTransfer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,9 @@ export class VeiledTransfer {

let veiledInvoiceAmount: VeiledAmount | undefined;
if (args.veiledInvoiceAmount) {
console.log("try to decrypt invoice payment");
veiledInvoiceAmount = await VeiledAmount.fromEncrypted(args.veiledInvoiceAmount, args.senderDecryptionKey);
console.log("decrypted invoice payment", veiledInvoiceAmount.amount);
}

let veiledMinTransferAmount: VeiledAmount | undefined;
Expand Down Expand Up @@ -349,7 +351,9 @@ export class VeiledTransfer {
);
let alpha7List: bigint[] | undefined;
if (this.veiledInvoiceAmount?.amountChunks?.length) {
alpha7List = x7List.slice(0, j).map((el, idx) => el - p * this.veiledInvoiceAmount!.amountChunks[idx]);
alpha7List = x7List
.slice(0, j)
.map((el, idx) => ed25519modN(el - p * this.veiledInvoiceAmount!.amountChunks[idx]));
}

return {
Expand All @@ -372,7 +376,7 @@ export class VeiledTransfer {
}

static verifySigmaProof(opts: {
senderPrivateKey: TwistedEd25519PrivateKey;
senderPublicKey: TwistedEd25519PublicKey;
recipientPublicKey: TwistedEd25519PublicKey;
encryptedActualBalance: TwistedElGamalCiphertext[];
encryptedActualBalanceAfterTransfer: TwistedElGamalCiphertext[];
Expand All @@ -397,7 +401,7 @@ export class VeiledTransfer {
const alpha6LEList = opts.sigmaProof.alpha6List.map((a) => bytesToNumberLE(a));
// const alpha7LEList = opts.sigmaProof.alpha7List?.map((a) => bytesToNumberLE(a)) ?? [];

const senderPublicKeyU8 = publicKeyToU8(opts.senderPrivateKey.publicKey());
const senderPublicKeyU8 = publicKeyToU8(opts.senderPublicKey);
const recipientPublicKeyU8 = publicKeyToU8(opts.recipientPublicKey);
const senderPKRistretto = RistrettoPoint.fromHex(senderPublicKeyU8);
const recipientPKRistretto = RistrettoPoint.fromHex(recipientPublicKeyU8);
Expand Down Expand Up @@ -498,6 +502,17 @@ export class VeiledTransfer {
);
}

console.log({
X1: X1.equals(RistrettoPoint.fromHex(opts.sigmaProof.X1)),
X2List: X2List.every((X2, i) => X2.equals(RistrettoPoint.fromHex(opts.sigmaProof.X2List[i]))),
X3List: X3List.every((X3, i) => X3.equals(RistrettoPoint.fromHex(opts.sigmaProof.X3List[i]))),
X4List: X4List.every((X4, i) => X4.equals(RistrettoPoint.fromHex(opts.sigmaProof.X4List[i]))),
X5: X5.equals(RistrettoPoint.fromHex(opts.sigmaProof.X5)),
X6List: X6List.every((X6, i) => X6.equals(RistrettoPoint.fromHex(opts.sigmaProof.X6List[i]))),
X7List: X7List.flat().every((X7, i) => X7.equals(RistrettoPoint.fromHex(proofX7List[i]))),
X8List: X8List.flat().every((X8, i) => X8.equals(RistrettoPoint.fromHex(proofX8List[i]))),
});

return (
X1.equals(RistrettoPoint.fromHex(opts.sigmaProof.X1)) &&
X2List.every((X2, i) => X2.equals(RistrettoPoint.fromHex(opts.sigmaProof.X2List[i]))) &&
Expand Down
Loading

0 comments on commit b7e664d

Please sign in to comment.