-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathFiniteField.ts
126 lines (116 loc) · 2.91 KB
/
FiniteField.ts
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
import { mod, pow } from "./util/BigIntMath";
/**
* This class encapsulates a finite field with order P. This class
* defines various math operations under fp.
*/
export class FiniteField {
/**
* @param p prime value
*/
constructor(readonly p: bigint) {}
/**
* Returns a value converted into a valid value in the field. This
* takes the form `a % p`
* @param a
*/
public mod(a: bigint): bigint {
return mod(a, this.p);
}
/**
* Throws if the value is not in the field
* @param a
*/
public assert(a: bigint): void {
if (a < 0 || a >= this.p) {
throw new Error("value is not in field");
}
}
/**
* Adds two numbers in the same Field by using the formula:
* `(a + b) % p`
*/
public add(a: bigint, b: bigint): bigint {
this.assert(a);
this.assert(b);
return mod(a + b, this.p);
}
/**
* Subtracts two nubmers in the same Field by using the formula:
* `(a - b) % p`
*
* @remarks
* This fixes the negative mod issues in JavaScript by using the
* `mod` helper which uses the formula:
* ```
* (n + p) % p
* ```
*/
public sub(a: bigint, b: bigint): bigint {
this.assert(a);
this.assert(b);
return mod(a - b, this.p);
}
/**
* Multiplies two field elements together using the formula:
*
* ```
* (a * b) % p
* ```
*/
public mul(a: bigint, b: bigint): bigint {
this.assert(a);
this.assert(b);
return mod(a * b, this.p);
}
/**
* 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
* ```
*/
public div(a: bigint, b: bigint): bigint {
this.assert(a);
this.assert(b);
return mod(a * pow(b, this.p - 2n, this.p), this.p);
}
/**
* Raises the provided value to the exponent. We first force the
* exponent to be positive using Fermats Little Theorem. This uses
* the formula:
*
* ```
* b = b % (p - 1)
* (a^b) % p
* ```
*/
public pow(a: bigint, e: bigint): bigint {
e = mod(e, this.p - 1n);
return pow(a, e, this.p);
}
/**
* Negates the field value with the formula `p-n`. This follows from
* ```
* n + (p - n) = 0;
* ```
*/
public neg(a: bigint): bigint {
return this.p - a;
}
/**
* Calculate the sqrt of the finite field which is possible if
* `p % 4 = 3`. The formula for this is:
*
* ```
* v^((P + 1) / 4)
* ```
*/
public sqrt(a: bigint): bigint {
if (this.p % 4n !== 3n) {
throw new Error("No algorithm for sqrt");
}
return this.pow(a, (this.p + 1n) / 4n);
}
}