From d37137070076314e042f1926df055235ee479a27 Mon Sep 17 00:00:00 2001 From: malatrax Date: Mon, 29 Apr 2024 13:17:00 +0200 Subject: [PATCH] feat: add felt division based on binary exponentiation --- src/primitives/felt.test.ts | 21 ++++++++------------- src/primitives/felt.ts | 27 ++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/src/primitives/felt.test.ts b/src/primitives/felt.test.ts index 41bb3839..2b27db46 100644 --- a/src/primitives/felt.test.ts +++ b/src/primitives/felt.test.ts @@ -107,19 +107,14 @@ describe('Felt', () => { }); describe('div', () => { - test('should divide two felts properly', () => { - const a = new Felt(10n); - const b = new Felt(2n); - const result = a.div(b); - const expected = new Felt(5n); - expect(result.eq(expected)).toBeTrue(); - }); - test('should go to 0 if a < b in a/b', () => { - const a = new Felt(5n); - const b = new Felt(10n); - const result = a.div(b); - const expected = new Felt(0n); - expect(result.eq(expected)).toBeTrue(); + test.each([ + [new Felt(10n), new Felt(2n)], + [new Felt(5n), new Felt(10n)], + [new Felt(Felt.PRIME - 10n), new Felt(10n)], + [new Felt(10n), new Felt(Felt.PRIME - 10n)], + ])('should divide two felts properly', (a: Felt, b: Felt) => { + const result = a.div(b).mul(b); + expect(result).toStrictEqual(a); }); }); }); diff --git a/src/primitives/felt.ts b/src/primitives/felt.ts index 24b4570e..4a229aa4 100644 --- a/src/primitives/felt.ts +++ b/src/primitives/felt.ts @@ -42,7 +42,8 @@ export class Felt { if (!isFelt(other) || other.inner === 0n) { throw new ForbiddenOperation(); } - return new Felt(this.inner / other.inner); + + return this.mul(other.inv()); } eq(other: MaybeRelocatable): boolean { @@ -60,4 +61,28 @@ export class Felt { toHexString(): string { return this.inner.toString(16); } + + /** + * @dev Compute modular multiplicative inverse with + * Euler totient's function and Fermat's little theorem + */ + private inv(): Felt { + return this.pow(Felt.PRIME - 2n); + } + + /** @dev Binary Exponentiation - Iterative version */ + private pow(exp: bigint): Felt { + if (exp === 0n) return new Felt(1n); + if (exp === 1n) return this; + let res = 1n; + let inner = this.inner; + while (exp !== 0n) { + if (exp & 1n) { + res = (res * inner) % Felt.PRIME; + } + inner = (inner * inner) % Felt.PRIME; + exp >>= 1n; + } + return new Felt(res); + } }