nanocurrency 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.travis.yml +7 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +40 -0
- data/LICENSE.txt +21 -0
- data/README.md +43 -0
- data/Rakefile +16 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/ext/.DS_Store +0 -0
- data/ext/nanocurrency_ext/blake2-config.h +72 -0
- data/ext/nanocurrency_ext/blake2-impl.h +160 -0
- data/ext/nanocurrency_ext/blake2.h +195 -0
- data/ext/nanocurrency_ext/blake2b-load-sse2.h +68 -0
- data/ext/nanocurrency_ext/blake2b-load-sse41.h +402 -0
- data/ext/nanocurrency_ext/blake2b-ref.c +373 -0
- data/ext/nanocurrency_ext/blake2b-round.h +157 -0
- data/ext/nanocurrency_ext/curve25519-donna-32bit.h +579 -0
- data/ext/nanocurrency_ext/curve25519-donna-64bit.h +413 -0
- data/ext/nanocurrency_ext/curve25519-donna-helpers.h +67 -0
- data/ext/nanocurrency_ext/curve25519-donna-sse2.h +1112 -0
- data/ext/nanocurrency_ext/ed25519-donna-32bit-sse2.h +513 -0
- data/ext/nanocurrency_ext/ed25519-donna-32bit-tables.h +61 -0
- data/ext/nanocurrency_ext/ed25519-donna-64bit-sse2.h +436 -0
- data/ext/nanocurrency_ext/ed25519-donna-64bit-tables.h +53 -0
- data/ext/nanocurrency_ext/ed25519-donna-64bit-x86-32bit.h +435 -0
- data/ext/nanocurrency_ext/ed25519-donna-64bit-x86.h +351 -0
- data/ext/nanocurrency_ext/ed25519-donna-basepoint-table.h +259 -0
- data/ext/nanocurrency_ext/ed25519-donna-batchverify.h +275 -0
- data/ext/nanocurrency_ext/ed25519-donna-impl-base.h +364 -0
- data/ext/nanocurrency_ext/ed25519-donna-impl-sse2.h +390 -0
- data/ext/nanocurrency_ext/ed25519-donna-portable-identify.h +103 -0
- data/ext/nanocurrency_ext/ed25519-donna-portable.h +135 -0
- data/ext/nanocurrency_ext/ed25519-donna.h +115 -0
- data/ext/nanocurrency_ext/ed25519-hash-custom.c +28 -0
- data/ext/nanocurrency_ext/ed25519-hash-custom.h +30 -0
- data/ext/nanocurrency_ext/ed25519-hash.h +219 -0
- data/ext/nanocurrency_ext/ed25519-randombytes-custom.h +10 -0
- data/ext/nanocurrency_ext/ed25519-randombytes.h +91 -0
- data/ext/nanocurrency_ext/ed25519.c +150 -0
- data/ext/nanocurrency_ext/ed25519.h +30 -0
- data/ext/nanocurrency_ext/extconf.rb +3 -0
- data/ext/nanocurrency_ext/fuzz/README.md +173 -0
- data/ext/nanocurrency_ext/fuzz/build-nix.php +134 -0
- data/ext/nanocurrency_ext/fuzz/curve25519-ref10.c +1272 -0
- data/ext/nanocurrency_ext/fuzz/curve25519-ref10.h +8 -0
- data/ext/nanocurrency_ext/fuzz/ed25519-donna-sse2.c +3 -0
- data/ext/nanocurrency_ext/fuzz/ed25519-donna.c +1 -0
- data/ext/nanocurrency_ext/fuzz/ed25519-donna.h +34 -0
- data/ext/nanocurrency_ext/fuzz/ed25519-ref10.c +4647 -0
- data/ext/nanocurrency_ext/fuzz/ed25519-ref10.h +9 -0
- data/ext/nanocurrency_ext/fuzz/fuzz-curve25519.c +172 -0
- data/ext/nanocurrency_ext/fuzz/fuzz-ed25519.c +219 -0
- data/ext/nanocurrency_ext/modm-donna-32bit.h +469 -0
- data/ext/nanocurrency_ext/modm-donna-64bit.h +361 -0
- data/ext/nanocurrency_ext/rbext.c +164 -0
- data/ext/nanocurrency_ext/regression.h +1024 -0
- data/lib/nano/account.rb +59 -0
- data/lib/nano/base32.rb +87 -0
- data/lib/nano/block.rb +142 -0
- data/lib/nano/check.rb +65 -0
- data/lib/nano/conversion.rb +102 -0
- data/lib/nano/hash.rb +43 -0
- data/lib/nano/key.rb +69 -0
- data/lib/nano/utils.rb +45 -0
- data/lib/nano/work.rb +51 -0
- data/lib/nanocurrency.rb +7 -0
- data/lib/nanocurrency/version.rb +3 -0
- data/lib/nanocurrency_ext.bundle +0 -0
- data/nanocurrency.gemspec +44 -0
- metadata +192 -0
@@ -0,0 +1,361 @@
|
|
1
|
+
/*
|
2
|
+
Public domain by Andrew M. <liquidsun@gmail.com>
|
3
|
+
*/
|
4
|
+
|
5
|
+
|
6
|
+
/*
|
7
|
+
Arithmetic modulo the group order n = 2^252 + 27742317777372353535851937790883648493 = 7237005577332262213973186563042994240857116359379907606001950938285454250989
|
8
|
+
|
9
|
+
k = 32
|
10
|
+
b = 1 << 8 = 256
|
11
|
+
m = 2^252 + 27742317777372353535851937790883648493 = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed
|
12
|
+
mu = floor( b^(k*2) / m ) = 0xfffffffffffffffffffffffffffffffeb2106215d086329a7ed9ce5a30a2c131b
|
13
|
+
*/
|
14
|
+
|
15
|
+
#define bignum256modm_bits_per_limb 56
|
16
|
+
#define bignum256modm_limb_size 5
|
17
|
+
|
18
|
+
typedef uint64_t bignum256modm_element_t;
|
19
|
+
typedef bignum256modm_element_t bignum256modm[5];
|
20
|
+
|
21
|
+
static const bignum256modm modm_m = {
|
22
|
+
0x12631a5cf5d3ed,
|
23
|
+
0xf9dea2f79cd658,
|
24
|
+
0x000000000014de,
|
25
|
+
0x00000000000000,
|
26
|
+
0x00000010000000
|
27
|
+
};
|
28
|
+
|
29
|
+
static const bignum256modm modm_mu = {
|
30
|
+
0x9ce5a30a2c131b,
|
31
|
+
0x215d086329a7ed,
|
32
|
+
0xffffffffeb2106,
|
33
|
+
0xffffffffffffff,
|
34
|
+
0x00000fffffffff
|
35
|
+
};
|
36
|
+
|
37
|
+
static bignum256modm_element_t
|
38
|
+
lt_modm(bignum256modm_element_t a, bignum256modm_element_t b) {
|
39
|
+
return (a - b) >> 63;
|
40
|
+
}
|
41
|
+
|
42
|
+
static void
|
43
|
+
reduce256_modm(bignum256modm r) {
|
44
|
+
bignum256modm t;
|
45
|
+
bignum256modm_element_t b = 0, pb, mask;
|
46
|
+
|
47
|
+
/* t = r - m */
|
48
|
+
pb = 0;
|
49
|
+
pb += modm_m[0]; b = lt_modm(r[0], pb); t[0] = (r[0] - pb + (b << 56)); pb = b;
|
50
|
+
pb += modm_m[1]; b = lt_modm(r[1], pb); t[1] = (r[1] - pb + (b << 56)); pb = b;
|
51
|
+
pb += modm_m[2]; b = lt_modm(r[2], pb); t[2] = (r[2] - pb + (b << 56)); pb = b;
|
52
|
+
pb += modm_m[3]; b = lt_modm(r[3], pb); t[3] = (r[3] - pb + (b << 56)); pb = b;
|
53
|
+
pb += modm_m[4]; b = lt_modm(r[4], pb); t[4] = (r[4] - pb + (b << 32));
|
54
|
+
|
55
|
+
/* keep r if r was smaller than m */
|
56
|
+
mask = b - 1;
|
57
|
+
|
58
|
+
r[0] ^= mask & (r[0] ^ t[0]);
|
59
|
+
r[1] ^= mask & (r[1] ^ t[1]);
|
60
|
+
r[2] ^= mask & (r[2] ^ t[2]);
|
61
|
+
r[3] ^= mask & (r[3] ^ t[3]);
|
62
|
+
r[4] ^= mask & (r[4] ^ t[4]);
|
63
|
+
}
|
64
|
+
|
65
|
+
static void
|
66
|
+
barrett_reduce256_modm(bignum256modm r, const bignum256modm q1, const bignum256modm r1) {
|
67
|
+
bignum256modm q3, r2;
|
68
|
+
uint128_t c, mul;
|
69
|
+
bignum256modm_element_t f, b, pb;
|
70
|
+
|
71
|
+
/* q1 = x >> 248 = 264 bits = 5 56 bit elements
|
72
|
+
q2 = mu * q1
|
73
|
+
q3 = (q2 / 256(32+1)) = q2 / (2^8)^(32+1) = q2 >> 264 */
|
74
|
+
mul64x64_128(c, modm_mu[0], q1[3]) mul64x64_128(mul, modm_mu[3], q1[0]) add128(c, mul) mul64x64_128(mul, modm_mu[1], q1[2]) add128(c, mul) mul64x64_128(mul, modm_mu[2], q1[1]) add128(c, mul) shr128(f, c, 56);
|
75
|
+
mul64x64_128(c, modm_mu[0], q1[4]) add128_64(c, f) mul64x64_128(mul, modm_mu[4], q1[0]) add128(c, mul) mul64x64_128(mul, modm_mu[3], q1[1]) add128(c, mul) mul64x64_128(mul, modm_mu[1], q1[3]) add128(c, mul) mul64x64_128(mul, modm_mu[2], q1[2]) add128(c, mul)
|
76
|
+
f = lo128(c); q3[0] = (f >> 40) & 0xffff; shr128(f, c, 56);
|
77
|
+
mul64x64_128(c, modm_mu[4], q1[1]) add128_64(c, f) mul64x64_128(mul, modm_mu[1], q1[4]) add128(c, mul) mul64x64_128(mul, modm_mu[2], q1[3]) add128(c, mul) mul64x64_128(mul, modm_mu[3], q1[2]) add128(c, mul)
|
78
|
+
f = lo128(c); q3[0] |= (f << 16) & 0xffffffffffffff; q3[1] = (f >> 40) & 0xffff; shr128(f, c, 56);
|
79
|
+
mul64x64_128(c, modm_mu[4], q1[2]) add128_64(c, f) mul64x64_128(mul, modm_mu[2], q1[4]) add128(c, mul) mul64x64_128(mul, modm_mu[3], q1[3]) add128(c, mul)
|
80
|
+
f = lo128(c); q3[1] |= (f << 16) & 0xffffffffffffff; q3[2] = (f >> 40) & 0xffff; shr128(f, c, 56);
|
81
|
+
mul64x64_128(c, modm_mu[4], q1[3]) add128_64(c, f) mul64x64_128(mul, modm_mu[3], q1[4]) add128(c, mul)
|
82
|
+
f = lo128(c); q3[2] |= (f << 16) & 0xffffffffffffff; q3[3] = (f >> 40) & 0xffff; shr128(f, c, 56);
|
83
|
+
mul64x64_128(c, modm_mu[4], q1[4]) add128_64(c, f)
|
84
|
+
f = lo128(c); q3[3] |= (f << 16) & 0xffffffffffffff; q3[4] = (f >> 40) & 0xffff; shr128(f, c, 56);
|
85
|
+
q3[4] |= (f << 16);
|
86
|
+
|
87
|
+
mul64x64_128(c, modm_m[0], q3[0])
|
88
|
+
r2[0] = lo128(c) & 0xffffffffffffff; shr128(f, c, 56);
|
89
|
+
mul64x64_128(c, modm_m[0], q3[1]) add128_64(c, f) mul64x64_128(mul, modm_m[1], q3[0]) add128(c, mul)
|
90
|
+
r2[1] = lo128(c) & 0xffffffffffffff; shr128(f, c, 56);
|
91
|
+
mul64x64_128(c, modm_m[0], q3[2]) add128_64(c, f) mul64x64_128(mul, modm_m[2], q3[0]) add128(c, mul) mul64x64_128(mul, modm_m[1], q3[1]) add128(c, mul)
|
92
|
+
r2[2] = lo128(c) & 0xffffffffffffff; shr128(f, c, 56);
|
93
|
+
mul64x64_128(c, modm_m[0], q3[3]) add128_64(c, f) mul64x64_128(mul, modm_m[3], q3[0]) add128(c, mul) mul64x64_128(mul, modm_m[1], q3[2]) add128(c, mul) mul64x64_128(mul, modm_m[2], q3[1]) add128(c, mul)
|
94
|
+
r2[3] = lo128(c) & 0xffffffffffffff; shr128(f, c, 56);
|
95
|
+
mul64x64_128(c, modm_m[0], q3[4]) add128_64(c, f) mul64x64_128(mul, modm_m[4], q3[0]) add128(c, mul) mul64x64_128(mul, modm_m[3], q3[1]) add128(c, mul) mul64x64_128(mul, modm_m[1], q3[3]) add128(c, mul) mul64x64_128(mul, modm_m[2], q3[2]) add128(c, mul)
|
96
|
+
r2[4] = lo128(c) & 0x0000ffffffffff;
|
97
|
+
|
98
|
+
pb = 0;
|
99
|
+
pb += r2[0]; b = lt_modm(r1[0], pb); r[0] = (r1[0] - pb + (b << 56)); pb = b;
|
100
|
+
pb += r2[1]; b = lt_modm(r1[1], pb); r[1] = (r1[1] - pb + (b << 56)); pb = b;
|
101
|
+
pb += r2[2]; b = lt_modm(r1[2], pb); r[2] = (r1[2] - pb + (b << 56)); pb = b;
|
102
|
+
pb += r2[3]; b = lt_modm(r1[3], pb); r[3] = (r1[3] - pb + (b << 56)); pb = b;
|
103
|
+
pb += r2[4]; b = lt_modm(r1[4], pb); r[4] = (r1[4] - pb + (b << 40));
|
104
|
+
|
105
|
+
reduce256_modm(r);
|
106
|
+
reduce256_modm(r);
|
107
|
+
}
|
108
|
+
|
109
|
+
|
110
|
+
static void
|
111
|
+
add256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) {
|
112
|
+
bignum256modm_element_t c;
|
113
|
+
|
114
|
+
c = x[0] + y[0]; r[0] = c & 0xffffffffffffff; c >>= 56;
|
115
|
+
c += x[1] + y[1]; r[1] = c & 0xffffffffffffff; c >>= 56;
|
116
|
+
c += x[2] + y[2]; r[2] = c & 0xffffffffffffff; c >>= 56;
|
117
|
+
c += x[3] + y[3]; r[3] = c & 0xffffffffffffff; c >>= 56;
|
118
|
+
c += x[4] + y[4]; r[4] = c;
|
119
|
+
|
120
|
+
reduce256_modm(r);
|
121
|
+
}
|
122
|
+
|
123
|
+
static void
|
124
|
+
mul256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) {
|
125
|
+
bignum256modm q1, r1;
|
126
|
+
uint128_t c, mul;
|
127
|
+
bignum256modm_element_t f;
|
128
|
+
|
129
|
+
mul64x64_128(c, x[0], y[0])
|
130
|
+
f = lo128(c); r1[0] = f & 0xffffffffffffff; shr128(f, c, 56);
|
131
|
+
mul64x64_128(c, x[0], y[1]) add128_64(c, f) mul64x64_128(mul, x[1], y[0]) add128(c, mul)
|
132
|
+
f = lo128(c); r1[1] = f & 0xffffffffffffff; shr128(f, c, 56);
|
133
|
+
mul64x64_128(c, x[0], y[2]) add128_64(c, f) mul64x64_128(mul, x[2], y[0]) add128(c, mul) mul64x64_128(mul, x[1], y[1]) add128(c, mul)
|
134
|
+
f = lo128(c); r1[2] = f & 0xffffffffffffff; shr128(f, c, 56);
|
135
|
+
mul64x64_128(c, x[0], y[3]) add128_64(c, f) mul64x64_128(mul, x[3], y[0]) add128(c, mul) mul64x64_128(mul, x[1], y[2]) add128(c, mul) mul64x64_128(mul, x[2], y[1]) add128(c, mul)
|
136
|
+
f = lo128(c); r1[3] = f & 0xffffffffffffff; shr128(f, c, 56);
|
137
|
+
mul64x64_128(c, x[0], y[4]) add128_64(c, f) mul64x64_128(mul, x[4], y[0]) add128(c, mul) mul64x64_128(mul, x[3], y[1]) add128(c, mul) mul64x64_128(mul, x[1], y[3]) add128(c, mul) mul64x64_128(mul, x[2], y[2]) add128(c, mul)
|
138
|
+
f = lo128(c); r1[4] = f & 0x0000ffffffffff; q1[0] = (f >> 24) & 0xffffffff; shr128(f, c, 56);
|
139
|
+
mul64x64_128(c, x[4], y[1]) add128_64(c, f) mul64x64_128(mul, x[1], y[4]) add128(c, mul) mul64x64_128(mul, x[2], y[3]) add128(c, mul) mul64x64_128(mul, x[3], y[2]) add128(c, mul)
|
140
|
+
f = lo128(c); q1[0] |= (f << 32) & 0xffffffffffffff; q1[1] = (f >> 24) & 0xffffffff; shr128(f, c, 56);
|
141
|
+
mul64x64_128(c, x[4], y[2]) add128_64(c, f) mul64x64_128(mul, x[2], y[4]) add128(c, mul) mul64x64_128(mul, x[3], y[3]) add128(c, mul)
|
142
|
+
f = lo128(c); q1[1] |= (f << 32) & 0xffffffffffffff; q1[2] = (f >> 24) & 0xffffffff; shr128(f, c, 56);
|
143
|
+
mul64x64_128(c, x[4], y[3]) add128_64(c, f) mul64x64_128(mul, x[3], y[4]) add128(c, mul)
|
144
|
+
f = lo128(c); q1[2] |= (f << 32) & 0xffffffffffffff; q1[3] = (f >> 24) & 0xffffffff; shr128(f, c, 56);
|
145
|
+
mul64x64_128(c, x[4], y[4]) add128_64(c, f)
|
146
|
+
f = lo128(c); q1[3] |= (f << 32) & 0xffffffffffffff; q1[4] = (f >> 24) & 0xffffffff; shr128(f, c, 56);
|
147
|
+
q1[4] |= (f << 32);
|
148
|
+
|
149
|
+
barrett_reduce256_modm(r, q1, r1);
|
150
|
+
}
|
151
|
+
|
152
|
+
static void
|
153
|
+
expand256_modm(bignum256modm out, const unsigned char *in, size_t len) {
|
154
|
+
unsigned char work[64] = {0};
|
155
|
+
bignum256modm_element_t x[16];
|
156
|
+
bignum256modm q1;
|
157
|
+
|
158
|
+
memcpy(work, in, len);
|
159
|
+
x[0] = U8TO64_LE(work + 0);
|
160
|
+
x[1] = U8TO64_LE(work + 8);
|
161
|
+
x[2] = U8TO64_LE(work + 16);
|
162
|
+
x[3] = U8TO64_LE(work + 24);
|
163
|
+
x[4] = U8TO64_LE(work + 32);
|
164
|
+
x[5] = U8TO64_LE(work + 40);
|
165
|
+
x[6] = U8TO64_LE(work + 48);
|
166
|
+
x[7] = U8TO64_LE(work + 56);
|
167
|
+
|
168
|
+
/* r1 = (x mod 256^(32+1)) = x mod (2^8)(31+1) = x & ((1 << 264) - 1) */
|
169
|
+
out[0] = ( x[0]) & 0xffffffffffffff;
|
170
|
+
out[1] = ((x[ 0] >> 56) | (x[ 1] << 8)) & 0xffffffffffffff;
|
171
|
+
out[2] = ((x[ 1] >> 48) | (x[ 2] << 16)) & 0xffffffffffffff;
|
172
|
+
out[3] = ((x[ 2] >> 40) | (x[ 3] << 24)) & 0xffffffffffffff;
|
173
|
+
out[4] = ((x[ 3] >> 32) | (x[ 4] << 32)) & 0x0000ffffffffff;
|
174
|
+
|
175
|
+
/* under 252 bits, no need to reduce */
|
176
|
+
if (len < 32)
|
177
|
+
return;
|
178
|
+
|
179
|
+
/* q1 = x >> 248 = 264 bits */
|
180
|
+
q1[0] = ((x[ 3] >> 56) | (x[ 4] << 8)) & 0xffffffffffffff;
|
181
|
+
q1[1] = ((x[ 4] >> 48) | (x[ 5] << 16)) & 0xffffffffffffff;
|
182
|
+
q1[2] = ((x[ 5] >> 40) | (x[ 6] << 24)) & 0xffffffffffffff;
|
183
|
+
q1[3] = ((x[ 6] >> 32) | (x[ 7] << 32)) & 0xffffffffffffff;
|
184
|
+
q1[4] = ((x[ 7] >> 24) );
|
185
|
+
|
186
|
+
barrett_reduce256_modm(out, q1, out);
|
187
|
+
}
|
188
|
+
|
189
|
+
static void
|
190
|
+
expand_raw256_modm(bignum256modm out, const unsigned char in[32]) {
|
191
|
+
bignum256modm_element_t x[4];
|
192
|
+
|
193
|
+
x[0] = U8TO64_LE(in + 0);
|
194
|
+
x[1] = U8TO64_LE(in + 8);
|
195
|
+
x[2] = U8TO64_LE(in + 16);
|
196
|
+
x[3] = U8TO64_LE(in + 24);
|
197
|
+
|
198
|
+
out[0] = ( x[0]) & 0xffffffffffffff;
|
199
|
+
out[1] = ((x[ 0] >> 56) | (x[ 1] << 8)) & 0xffffffffffffff;
|
200
|
+
out[2] = ((x[ 1] >> 48) | (x[ 2] << 16)) & 0xffffffffffffff;
|
201
|
+
out[3] = ((x[ 2] >> 40) | (x[ 3] << 24)) & 0xffffffffffffff;
|
202
|
+
out[4] = ((x[ 3] >> 32) ) & 0x000000ffffffff;
|
203
|
+
}
|
204
|
+
|
205
|
+
static void
|
206
|
+
contract256_modm(unsigned char out[32], const bignum256modm in) {
|
207
|
+
U64TO8_LE(out + 0, (in[0] ) | (in[1] << 56));
|
208
|
+
U64TO8_LE(out + 8, (in[1] >> 8) | (in[2] << 48));
|
209
|
+
U64TO8_LE(out + 16, (in[2] >> 16) | (in[3] << 40));
|
210
|
+
U64TO8_LE(out + 24, (in[3] >> 24) | (in[4] << 32));
|
211
|
+
}
|
212
|
+
|
213
|
+
static void
|
214
|
+
contract256_window4_modm(signed char r[64], const bignum256modm in) {
|
215
|
+
char carry;
|
216
|
+
signed char *quads = r;
|
217
|
+
bignum256modm_element_t i, j, v, m;
|
218
|
+
|
219
|
+
for (i = 0; i < 5; i++) {
|
220
|
+
v = in[i];
|
221
|
+
m = (i == 4) ? 8 : 14;
|
222
|
+
for (j = 0; j < m; j++) {
|
223
|
+
*quads++ = (v & 15);
|
224
|
+
v >>= 4;
|
225
|
+
}
|
226
|
+
}
|
227
|
+
|
228
|
+
/* making it signed */
|
229
|
+
carry = 0;
|
230
|
+
for(i = 0; i < 63; i++) {
|
231
|
+
r[i] += carry;
|
232
|
+
r[i+1] += (r[i] >> 4);
|
233
|
+
r[i] &= 15;
|
234
|
+
carry = (r[i] >> 3);
|
235
|
+
r[i] -= (carry << 4);
|
236
|
+
}
|
237
|
+
r[63] += carry;
|
238
|
+
}
|
239
|
+
|
240
|
+
static void
|
241
|
+
contract256_slidingwindow_modm(signed char r[256], const bignum256modm s, int windowsize) {
|
242
|
+
int i,j,k,b;
|
243
|
+
int m = (1 << (windowsize - 1)) - 1, soplen = 256;
|
244
|
+
signed char *bits = r;
|
245
|
+
bignum256modm_element_t v;
|
246
|
+
|
247
|
+
/* first put the binary expansion into r */
|
248
|
+
for (i = 0; i < 4; i++) {
|
249
|
+
v = s[i];
|
250
|
+
for (j = 0; j < 56; j++, v >>= 1)
|
251
|
+
*bits++ = (v & 1);
|
252
|
+
}
|
253
|
+
v = s[4];
|
254
|
+
for (j = 0; j < 32; j++, v >>= 1)
|
255
|
+
*bits++ = (v & 1);
|
256
|
+
|
257
|
+
/* Making it sliding window */
|
258
|
+
for (j = 0; j < soplen; j++) {
|
259
|
+
if (!r[j])
|
260
|
+
continue;
|
261
|
+
|
262
|
+
for (b = 1; (b < (soplen - j)) && (b <= 6); b++) {
|
263
|
+
if ((r[j] + (r[j + b] << b)) <= m) {
|
264
|
+
r[j] += r[j + b] << b;
|
265
|
+
r[j + b] = 0;
|
266
|
+
} else if ((r[j] - (r[j + b] << b)) >= -m) {
|
267
|
+
r[j] -= r[j + b] << b;
|
268
|
+
for (k = j + b; k < soplen; k++) {
|
269
|
+
if (!r[k]) {
|
270
|
+
r[k] = 1;
|
271
|
+
break;
|
272
|
+
}
|
273
|
+
r[k] = 0;
|
274
|
+
}
|
275
|
+
} else if (r[j + b]) {
|
276
|
+
break;
|
277
|
+
}
|
278
|
+
}
|
279
|
+
}
|
280
|
+
}
|
281
|
+
|
282
|
+
/*
|
283
|
+
helpers for batch verifcation, are allowed to be vartime
|
284
|
+
*/
|
285
|
+
|
286
|
+
/* out = a - b, a must be larger than b */
|
287
|
+
static void
|
288
|
+
sub256_modm_batch(bignum256modm out, const bignum256modm a, const bignum256modm b, size_t limbsize) {
|
289
|
+
size_t i = 0;
|
290
|
+
bignum256modm_element_t carry = 0;
|
291
|
+
switch (limbsize) {
|
292
|
+
case 4: out[i] = (a[i] - b[i]) ; carry = (out[i] >> 63); out[i] &= 0xffffffffffffff; i++;
|
293
|
+
case 3: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 63); out[i] &= 0xffffffffffffff; i++;
|
294
|
+
case 2: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 63); out[i] &= 0xffffffffffffff; i++;
|
295
|
+
case 1: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 63); out[i] &= 0xffffffffffffff; i++;
|
296
|
+
case 0:
|
297
|
+
default: out[i] = (a[i] - b[i]) - carry;
|
298
|
+
}
|
299
|
+
}
|
300
|
+
|
301
|
+
|
302
|
+
/* is a < b */
|
303
|
+
static int
|
304
|
+
lt256_modm_batch(const bignum256modm a, const bignum256modm b, size_t limbsize) {
|
305
|
+
size_t i = 0;
|
306
|
+
bignum256modm_element_t t, carry = 0;
|
307
|
+
switch (limbsize) {
|
308
|
+
case 4: t = (a[i] - b[i]) ; carry = (t >> 63); i++;
|
309
|
+
case 3: t = (a[i] - b[i]) - carry; carry = (t >> 63); i++;
|
310
|
+
case 2: t = (a[i] - b[i]) - carry; carry = (t >> 63); i++;
|
311
|
+
case 1: t = (a[i] - b[i]) - carry; carry = (t >> 63); i++;
|
312
|
+
case 0: t = (a[i] - b[i]) - carry; carry = (t >> 63);
|
313
|
+
}
|
314
|
+
return (int)carry;
|
315
|
+
}
|
316
|
+
|
317
|
+
/* is a <= b */
|
318
|
+
static int
|
319
|
+
lte256_modm_batch(const bignum256modm a, const bignum256modm b, size_t limbsize) {
|
320
|
+
size_t i = 0;
|
321
|
+
bignum256modm_element_t t, carry = 0;
|
322
|
+
switch (limbsize) {
|
323
|
+
case 4: t = (b[i] - a[i]) ; carry = (t >> 63); i++;
|
324
|
+
case 3: t = (b[i] - a[i]) - carry; carry = (t >> 63); i++;
|
325
|
+
case 2: t = (b[i] - a[i]) - carry; carry = (t >> 63); i++;
|
326
|
+
case 1: t = (b[i] - a[i]) - carry; carry = (t >> 63); i++;
|
327
|
+
case 0: t = (b[i] - a[i]) - carry; carry = (t >> 63);
|
328
|
+
}
|
329
|
+
return (int)!carry;
|
330
|
+
}
|
331
|
+
|
332
|
+
/* is a == 0 */
|
333
|
+
static int
|
334
|
+
iszero256_modm_batch(const bignum256modm a) {
|
335
|
+
size_t i;
|
336
|
+
for (i = 0; i < 5; i++)
|
337
|
+
if (a[i])
|
338
|
+
return 0;
|
339
|
+
return 1;
|
340
|
+
}
|
341
|
+
|
342
|
+
/* is a == 1 */
|
343
|
+
static int
|
344
|
+
isone256_modm_batch(const bignum256modm a) {
|
345
|
+
size_t i;
|
346
|
+
for (i = 0; i < 5; i++)
|
347
|
+
if (a[i] != ((i) ? 0 : 1))
|
348
|
+
return 0;
|
349
|
+
return 1;
|
350
|
+
}
|
351
|
+
|
352
|
+
/* can a fit in to (at most) 128 bits */
|
353
|
+
static int
|
354
|
+
isatmost128bits256_modm_batch(const bignum256modm a) {
|
355
|
+
uint64_t mask =
|
356
|
+
((a[4] ) | /* 32 */
|
357
|
+
(a[3] ) | /* 88 */
|
358
|
+
(a[2] & 0xffffffffff0000));
|
359
|
+
|
360
|
+
return (mask == 0);
|
361
|
+
}
|
@@ -0,0 +1,164 @@
|
|
1
|
+
#include <ruby/ruby.h>
|
2
|
+
#include <ruby/encoding.h>
|
3
|
+
#include "ed25519.h"
|
4
|
+
#include "blake2.h"
|
5
|
+
|
6
|
+
VALUE cNanocurrency;
|
7
|
+
|
8
|
+
const uint8_t WORK_HASH_LENGTH = 8;
|
9
|
+
const uint64_t WORK_THRESHOLD = 0xffffffc000000000;
|
10
|
+
const uint8_t BLOCK_HASH_LENGTH = 32;
|
11
|
+
const uint8_t WORK_LENGTH = 8;
|
12
|
+
|
13
|
+
void hex_to_bytes(const char* const hex, uint8_t* const dst) {
|
14
|
+
int byte_index = 0;
|
15
|
+
for (unsigned int i = 0; i < strlen(hex); i += 2) {
|
16
|
+
char byte_string[3];
|
17
|
+
memcpy(byte_string, hex + i, 2);
|
18
|
+
byte_string[2] = '\0';
|
19
|
+
const uint8_t byte = (uint8_t) strtol(byte_string, NULL, 16);
|
20
|
+
dst[byte_index++] = byte;
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
24
|
+
void uint64_to_bytes(const uint64_t src, uint8_t* const dst) {
|
25
|
+
memcpy(dst, &src, sizeof(src));
|
26
|
+
}
|
27
|
+
|
28
|
+
uint64_t bytes_to_uint64(const uint8_t* const src) {
|
29
|
+
uint64_t ret = 0;
|
30
|
+
|
31
|
+
memcpy(&ret, src, sizeof(ret));
|
32
|
+
|
33
|
+
return ret;
|
34
|
+
}
|
35
|
+
|
36
|
+
const uint8_t HEX_MAP[] = {'0', '1', '2', '3', '4', '5', '6', '7',
|
37
|
+
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
38
|
+
void bytes_to_hex(const uint8_t* const src, const uint8_t length, char* const dst) {
|
39
|
+
for (unsigned int i = 0; i < length; ++i) {
|
40
|
+
dst[2 * i] = HEX_MAP[(src[i] & 0xF0) >> 4];
|
41
|
+
dst[(2 * i) + 1] = HEX_MAP[src[i] & 0x0F];
|
42
|
+
}
|
43
|
+
|
44
|
+
dst[2 * length] = '\0';
|
45
|
+
}
|
46
|
+
|
47
|
+
|
48
|
+
void reverse_bytes(uint8_t* const src, const uint8_t length) {
|
49
|
+
for (unsigned int i = 0; i < (length / 2); i++) {
|
50
|
+
const uint8_t temp = src[i];
|
51
|
+
src[i] = src[(length - 1) - i];
|
52
|
+
src[(length - 1) - i] = temp;
|
53
|
+
}
|
54
|
+
}
|
55
|
+
|
56
|
+
uint8_t validate_work(const uint8_t* const block_hash, uint8_t* const work) {
|
57
|
+
blake2b_state hash;
|
58
|
+
uint8_t output[WORK_HASH_LENGTH];
|
59
|
+
|
60
|
+
blake2b_init(&hash, WORK_HASH_LENGTH);
|
61
|
+
blake2b_update(&hash, work, WORK_LENGTH);
|
62
|
+
blake2b_update(&hash, block_hash, BLOCK_HASH_LENGTH);
|
63
|
+
blake2b_final(&hash, output, WORK_HASH_LENGTH);
|
64
|
+
|
65
|
+
const uint64_t output_int = bytes_to_uint64(output);
|
66
|
+
|
67
|
+
return output_int >= WORK_THRESHOLD;
|
68
|
+
}
|
69
|
+
|
70
|
+
const uint64_t MIN_UINT64 = 0x0000000000000000;
|
71
|
+
const uint64_t MAX_UINT64 = 0xffffffffffffffff;
|
72
|
+
|
73
|
+
int work(const uint8_t* const block_hash, const uint8_t worker_index, const uint8_t worker_count, uint8_t* const dst) {
|
74
|
+
const uint64_t interval = (MAX_UINT64 - MIN_UINT64) / worker_count;
|
75
|
+
|
76
|
+
const uint64_t lower_bound = MIN_UINT64 + (worker_index * interval);
|
77
|
+
const uint64_t upper_bound = (worker_index != worker_count - 1) ? lower_bound + interval : MAX_UINT64;
|
78
|
+
|
79
|
+
uint64_t work = lower_bound;
|
80
|
+
uint8_t work_bytes[WORK_LENGTH];
|
81
|
+
|
82
|
+
for (;;) {
|
83
|
+
if (work == upper_bound) return -1;
|
84
|
+
|
85
|
+
uint64_to_bytes(work, work_bytes);
|
86
|
+
|
87
|
+
if (validate_work(block_hash, work_bytes)) {
|
88
|
+
reverse_bytes(work_bytes, WORK_LENGTH);
|
89
|
+
memcpy(dst, work_bytes, WORK_LENGTH);
|
90
|
+
return 0;
|
91
|
+
}
|
92
|
+
|
93
|
+
work++;
|
94
|
+
}
|
95
|
+
|
96
|
+
return -1;
|
97
|
+
}
|
98
|
+
|
99
|
+
VALUE nanocurrency_public_key(VALUE self, VALUE rbSecret_key) {
|
100
|
+
Check_Type(rbSecret_key, T_STRING);
|
101
|
+
if (RSTRING_LEN(rbSecret_key) != 32) {
|
102
|
+
rb_raise(rb_eArgError, "The secret key must be 32 bytes in length");
|
103
|
+
return Qnil;
|
104
|
+
}
|
105
|
+
|
106
|
+
unsigned char *secret_key = RSTRING_PTR(rbSecret_key);
|
107
|
+
|
108
|
+
ed25519_public_key public_key;
|
109
|
+
ed25519_publickey(secret_key, public_key);
|
110
|
+
|
111
|
+
return rb_str_new(public_key, 32);
|
112
|
+
}
|
113
|
+
|
114
|
+
VALUE nanocurrency_sign(VALUE self, VALUE rbHash, VALUE rbSecret_key) {
|
115
|
+
Check_Type(rbSecret_key, T_STRING);
|
116
|
+
Check_Type(rbHash, T_STRING);
|
117
|
+
|
118
|
+
if (RSTRING_LEN(rbSecret_key) != 32) {
|
119
|
+
rb_raise(rb_eArgError, "The secret key must be 32 bytes in length");
|
120
|
+
return Qnil;
|
121
|
+
}
|
122
|
+
|
123
|
+
if (RSTRING_LEN(rbHash) != 32) {
|
124
|
+
rb_raise(rb_eArgError, "The hash must be 32 bytes in length");
|
125
|
+
return Qnil;
|
126
|
+
}
|
127
|
+
|
128
|
+
unsigned char *secret_key = RSTRING_PTR(rbSecret_key);
|
129
|
+
unsigned char *message = RSTRING_PTR(rbHash);
|
130
|
+
ed25519_public_key public_key;
|
131
|
+
ed25519_publickey(secret_key, public_key);
|
132
|
+
size_t message_len = 32;
|
133
|
+
|
134
|
+
ed25519_signature sig;
|
135
|
+
ed25519_sign(message, message_len, secret_key, public_key, sig);
|
136
|
+
|
137
|
+
return rb_str_new(sig, 64);
|
138
|
+
}
|
139
|
+
|
140
|
+
VALUE nanocurrency_compute_work(VALUE self, VALUE rbHash) {
|
141
|
+
|
142
|
+
Check_Type(rbHash, T_STRING);
|
143
|
+
uint8_t block_hash_bytes[BLOCK_HASH_LENGTH];
|
144
|
+
const char *hex = RSTRING_PTR(rbHash);
|
145
|
+
hex_to_bytes(hex, block_hash_bytes);
|
146
|
+
|
147
|
+
char stack_string[WORK_LENGTH * 2];
|
148
|
+
uint8_t work_[WORK_LENGTH];
|
149
|
+
int res = work(block_hash_bytes, 0, 1, work_);
|
150
|
+
bytes_to_hex(work_, WORK_LENGTH, stack_string);
|
151
|
+
|
152
|
+
if (res == 0) {
|
153
|
+
return rb_str_new(stack_string, WORK_LENGTH * 2);
|
154
|
+
} else {
|
155
|
+
return Qnil;
|
156
|
+
}
|
157
|
+
}
|
158
|
+
|
159
|
+
void Init_nanocurrency_ext() {
|
160
|
+
cNanocurrency = rb_define_module("NanocurrencyExt");
|
161
|
+
rb_define_singleton_method(cNanocurrency, "public_key", nanocurrency_public_key, 1);
|
162
|
+
rb_define_singleton_method(cNanocurrency, "sign", nanocurrency_sign, 2);
|
163
|
+
rb_define_singleton_method(cNanocurrency, "compute_work", nanocurrency_compute_work, 1);
|
164
|
+
}
|