Skip to content

Commit f727191

Browse files
committed
updated bigint extension
1 parent 5c4ed33 commit f727191

File tree

3 files changed

+641
-85
lines changed

3 files changed

+641
-85
lines changed

examples/bigint.hk

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,15 @@
44

55
import bigint;
66

7-
let x = bigint.new("2222222222222222222222222222222222222222");
8-
let y = bigint.new("3333333333333333333333333333333333333333");
7+
let a = bigint.new("2222222222222222222222222222222222222222");
8+
let b = bigint.new(3);
9+
let c = bigint.from_string("f", 16);
10+
let d = bigint.new(7);
911

10-
let z = bigint.add(x, y);
12+
let x = bigint.add(a, b);
13+
let y = bigint.sub(x, c);
14+
let z = bigint.mod(y, d);
1115

16+
println(bigint.to_string(x));
17+
println(bigint.to_string(y));
1218
println(bigint.to_string(z));

examples/ecdsa.hk

Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
//
2+
// ecdsa.hk
3+
//
4+
5+
import bigint;
6+
import crypto;
7+
import hashing;
8+
9+
// Structs
10+
11+
struct Point {
12+
x, y
13+
}
14+
15+
struct Curve {
16+
keySize,
17+
A, B, P, N, G
18+
}
19+
20+
// Functions
21+
22+
fn new_point(x, y) {
23+
return Point {
24+
bigint.from_string(x, 16),
25+
bigint.from_string(y, 16)
26+
};
27+
}
28+
29+
fn new_point_at_infinity() {
30+
return Point { nil, nil };
31+
}
32+
33+
fn is_at_infinity(p) {
34+
return p.x == nil && p.y == nil;
35+
}
36+
37+
fn new_secp256k1_curve() {
38+
let G = new_point(
39+
"79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798",
40+
"483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"
41+
);
42+
return Curve {
43+
32,
44+
bigint.new(0),
45+
bigint.new(7),
46+
bigint.from_string(
47+
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F",
48+
16),
49+
bigint.from_string(
50+
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141",
51+
16),
52+
G
53+
};
54+
}
55+
56+
fn scalar_is_valid(c, scalar) {
57+
return bigint.compare(scalar, 0) > 0 && bigint.compare(scalar, c.N) < 0;
58+
}
59+
60+
fn random_scalar(c) {
61+
let size = c.keySize;
62+
var bytes = crypto.random_bytes(size);
63+
var scalar = bigint.from_bytes(bytes);
64+
while (!scalar_is_valid(c, scalar))
65+
{
66+
bytes = crypto.random_bytes(size);
67+
scalar = bigint.from_bytes(bytes);
68+
}
69+
return scalar;
70+
}
71+
72+
fn is_on_curve(c, p) {
73+
// p.y ^ 2 mod c.P = p.x ^ 3 + c.A * p.x + c.B mod c.P
74+
let t0 = bigint.mod(bigint.pow(p.y, 2), c.P);
75+
let t1 = bigint.pow(p.x, 3);
76+
let t2 = bigint.mul(c.A, p.x);
77+
let t3 = bigint.add(t1, bigint.add(t2, c.B));
78+
let t4 = bigint.mod(t3, c.P);
79+
return bigint.compare(t0, t4) == 0;
80+
}
81+
82+
fn compute_y(c, x) {
83+
// y0 = sqrtm_prime(x ^ 3 + c.A * x + c.B, c.P)
84+
// y1 = -y0 mod c.P
85+
let t0 = bigint.pow(x, 3);
86+
let t1 = bigint.mul(c.A, x);
87+
let t2 = bigint.add(t0, bigint.add(t1, c.B));
88+
let t3 = bigint.sqrtm_prime(t2, c.P);
89+
let t4 = bigint.mod(bigint.neg(t3), c.P);
90+
return [t3, t4];
91+
}
92+
93+
fn add_points(c, p, q) {
94+
if (is_at_infinity(p)) {
95+
return q;
96+
}
97+
if (is_at_infinity(q)) {
98+
return p;
99+
}
100+
// lambda = mod((q.y − p.y) * invertm(q.x − p.x, c.P), c.P)
101+
var t0 = bigint.sub(q.y, p.y);
102+
var t1 = bigint.sub(q.x, p.x);
103+
let t2 = bigint.invertm(t1, c.P);
104+
assert(t2, "invertm() failed");
105+
let t3 = bigint.mul(t0, t2);
106+
let lambda = bigint.mod(t3, c.P);
107+
// x = mod(lambda ^ 2 − p.x − q.x, c.P)
108+
t0 = bigint.sub(bigint.pow(lambda, 2), p.x);
109+
let x = bigint.mod(bigint.sub(t0, q.x), c.P);
110+
// y = mod(lambda * (p.x − x) − p.y, c.P)
111+
t0 = bigint.sub(p.x, x);
112+
t1 = bigint.mul(lambda, t0);
113+
let y = bigint.mod(bigint.sub(t1, p.y), c.P);
114+
return Point { x, y };
115+
}
116+
117+
fn double_point(c, p) {
118+
if (is_at_infinity(p) || bigint.compare(p.y, 0) == 0) {
119+
return new_point_at_infinity();
120+
}
121+
// lambda = mod((3 * p.x ^ 2 + c.A) * invertm(2 * p.y, c.P), c.P)
122+
var t0 = bigint.mul(bigint.pow(p.x, 2), 3);
123+
var t1 = bigint.add(t0, c.A);
124+
let t2 = bigint.mul(p.y, 2);
125+
let t3 = bigint.invertm(t2, c.P);
126+
assert(t3, "invertm() failed");
127+
let lambda = bigint.mod(bigint.mul(t1, t3), c.P);
128+
// x = mod(lambda ^ 2 − 2 * p.x, c.P)
129+
t0 = bigint.pow(lambda, 2);
130+
t1 = bigint.mul(p.x, 2);
131+
let x = bigint.mod(bigint.sub(t0, t1), c.P);
132+
// y = mod(lambda * (p.x − x) − p.y), c.P)
133+
t0 = bigint.sub(p.x, x);
134+
t1 = bigint.mul(lambda, t0);
135+
let y = bigint.mod(bigint.sub(t1, p.y), c.P);
136+
return Point { x, y };
137+
}
138+
139+
fn multiply_point_by_scalar(c, p, scalar)
140+
{
141+
var q = new_point_at_infinity();
142+
let n = bigint.size(scalar, 2);
143+
for (var i = n - 1; i >= 0; i--)
144+
{
145+
q = double_point(c, q);
146+
if (bigint.testbit(scalar, i) == 1) {
147+
q = add_points(c, q, p);
148+
}
149+
}
150+
return q;
151+
}
152+
153+
fn multiply_base_point_by_scalar(c, scalar) {
154+
return multiply_point_by_scalar(c, c.G, scalar);
155+
}
156+
157+
fn sign(c, digest, privKey) {
158+
if (!scalar_is_valid(c, privKey)) {
159+
return false;
160+
}
161+
loop {
162+
let k = random_scalar(c);
163+
let p = multiply_base_point_by_scalar(c, k);
164+
// r = mod(p.x, c.N)
165+
let r = bigint.mod(p.x, c.N);
166+
if (bigint.compare(r, 0) == 0) {
167+
continue;
168+
}
169+
// s = mod(invertm(k, c.N) * (digest + r * privKey), c.N)
170+
let t0 = bigint.mul(r, privKey);
171+
let t1 = bigint.add(digest, t0);
172+
let t2 = bigint.invertm(k, c.N);
173+
assert(t2, "invertm() failed");
174+
let s = bigint.mod(bigint.mul(t2, t1), c.N);
175+
if (bigint.compare(s, 0) == 0) {
176+
continue;
177+
}
178+
return [r, s];
179+
}
180+
}
181+
182+
fn verify_signature(c, digest, pubKey, r, s) {
183+
if (!scalar_is_valid(c, r) || !scalar_is_valid(c, s)) {
184+
return false;
185+
}
186+
// w = invertm(s, c.N)
187+
let w = bigint.invertm(s, c.N);
188+
assert(w, "invertm() failed");
189+
// u1 = mod(digest * w, c.N)
190+
let u1 = bigint.mod(bigint.mul(digest, w), c.N);
191+
// u2 = mod(r * w, c.N)
192+
let u2 = bigint.mod(bigint.mul(r, w), c.N);
193+
// p = u1 * G + u2 * pubKey
194+
let p = add_points(c,
195+
multiply_base_point_by_scalar(c, u1),
196+
multiply_point_by_scalar(c, pubKey, u2)
197+
);
198+
if (is_at_infinity(p)) {
199+
return false;
200+
}
201+
// v = mod(p.x, c.N)
202+
let v = bigint.mod(p.x, c.N);
203+
return bigint.compare(v, r) == 0;
204+
}
205+
206+
// Main
207+
208+
let c = new_secp256k1_curve();
209+
210+
// Test compute_y() and is_on_curve()
211+
let p = new_point(
212+
"D440BDBA94C11761FD4FC419B5BF3F111B8F193A5168ACD33AA5525DC50B2F18",
213+
"7E38B3F29FDF12904486A0BCCE8F5018B7B96B60661DAB6DC2CF73E843BEF6CE"
214+
);
215+
let isOnCurve = is_on_curve(c, p);
216+
assert(isOnCurve, "Point must be on curve");
217+
let [ y0, y1 ] = compute_y(c, p.x);
218+
let y0IsY = bigint.compare(y0, p.y) == 0;
219+
let y1IsY = bigint.compare(y1, p.y) == 0;
220+
assert(y0IsY || y1IsY, "Point must have valid y coordinate");
221+
222+
// Generate a random private key
223+
let privKey = random_scalar(c);
224+
println("Private key: " + bigint.to_string(privKey, 16));
225+
226+
// Get the public key
227+
let pubKey = multiply_base_point_by_scalar(c, privKey);
228+
println("Public key:");
229+
println(" x: " + bigint.to_string(pubKey.x, 16));
230+
println(" y: " + bigint.to_string(pubKey.y, 16));
231+
232+
// Hash the message
233+
let message = "Hello, world!";
234+
var digest = hashing.sha256(message);
235+
digest = bigint.from_bytes(digest);
236+
println("Digest: " + bigint.to_string(digest, 16));
237+
238+
// Sign the digest
239+
let [ r, s ] = sign(c, digest, privKey);
240+
println("Signature:");
241+
println(" r: " + bigint.to_string(r, 16));
242+
println(" s: " + bigint.to_string(s, 16));
243+
244+
// Verify the signature
245+
let isValid = verify_signature(c, digest, pubKey, r, s);
246+
assert(isValid, "Signature must be valid");

0 commit comments

Comments
 (0)