This repository was archived by the owner on May 14, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathFieldElement.ts
More file actions
131 lines (121 loc) · 3.41 KB
/
Copy pathFieldElement.ts
File metadata and controls
131 lines (121 loc) · 3.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import { IOperable } from "./Operable";
import { mod, pow } from "../util/BigIntMath";
/**
* Represents a finite field element which represents an elmement in the field
* F_prime.
*/
export class FieldElement implements IOperable {
constructor(readonly num: bigint, readonly prime: bigint) {
if (num >= prime || num < 0n) {
throw new Error(`Num ${num} not in field range 0 ${prime - 1n}`);
}
this.num = num;
this.prime = prime;
}
public toString() {
return `FieldElement_${this.prime}(${this.num})`;
}
/**
* Returns true when the other field element is equal to the
* current field element
* @param other
*/
public eq(other: FieldElement): boolean {
if (!other) return false;
return this.prime === other.prime && this.num === other.num;
}
/**
* Returns true when the other field element is not equal to the
* current field element
* @param other
*/
public neq(other: FieldElement): boolean {
return !this.eq(other);
}
/**
* Adds two numbers in the same Field by using the
* formula: `(a + b) % p`
*/
public add(other: FieldElement): FieldElement {
if (this.prime !== other.prime) {
throw new Error(`Cannot addd two numbers in different Fields`);
}
const num = mod(this.num + other.num, this.prime);
return new FieldElement(num, this.prime);
}
/**
*
* @remarks
* This fixes the negative mod bug using the formula:
*
* ```
* (n + p) % p
* ```
* @param other
*/
public sub(other: FieldElement): FieldElement {
if (this.prime !== other.prime) {
throw new Error(`Cannot add two numbers in different Fields`);
}
const num = mod(this.num - other.num, this.prime);
return new FieldElement(num, this.prime);
}
/**
* Multiplies two field elements together using the formula:
*
* ```
* (a * b) % p
* ```
* @param other
*/
public mul(other: FieldElement): FieldElement {
if (this.prime !== other.prime) {
throw new Error(`Cannot multiply two numbers in different Fields`);
}
const num = mod(this.num * other.num, this.prime);
return new FieldElement(num, this.prime);
}
/**
* Divides one number by another using Fermat's Little Theory which states that
* 1 = n^(p-1) % p and means we can find the inverse of using the formula
*
* ```
* (a * b ** (p - 2)) % p
* ```
* @param other
*/
public div(other: FieldElement): FieldElement {
if (this.prime !== other.prime) {
throw new Error(`Cannot divide two numbers in different Fields`);
}
const num = mod(
this.num * pow(other.num, this.prime - 2n, this.prime),
this.prime
);
return new FieldElement(num, this.prime);
}
/**
* Returns a new FieldElement with the value being the current number
* raised to the provided exponent. We first force the exponent to be positive
* using Fermats Little Theorem. This uses the formula:
*
* ```
* b = b % (p - 1)
* (a ** b) % p
* ```
* @param exponent
*/
public pow(exponent: bigint): FieldElement {
exponent = mod(exponent, this.prime - 1n);
const num = pow(this.num, exponent, this.prime);
return new FieldElement(num, this.prime);
}
/**
* Scalar multiple, which is the same as multiplier
* @param scalar
*/
public smul(scalar: bigint): FieldElement {
const num = mod(this.num * scalar, this.prime);
return new FieldElement(num, this.prime);
}
}