github.com/hhwill/poc-eth@v0.0.0-20240218063348-3bb107c90dbf/crypto/curve25519/curve25519.go (about) 1 package curve25519 2 3 import "bytes" 4 5 /* group order (a prime near 2^252+2^124) */ 6 var order = []byte{ 7 237, 211, 245, 92, 26, 99, 18, 88, 8 214, 156, 247, 162, 222, 249, 222, 20, 9 0, 0, 0, 0, 0, 0, 0, 0, 10 0, 0, 0, 0, 0, 0, 0, 16, 11 } 12 13 /* smallest multiple of the order that's >= 2^255 */ 14 var orderTimes8 = []byte{ 15 104, 159, 174, 231, 210, 24, 147, 192, 16 178, 230, 188, 23, 245, 206, 247, 166, 17 0, 0, 0, 0, 0, 0, 0, 0, 18 0, 0, 0, 0, 0, 0, 0, 128, 19 } 20 21 /* Private key clamping 22 * k [out] your private key for key agreement 23 * k [in] 32 random bytes 24 */ 25 func clamp(k []byte) { 26 k[31] &= 0x7F 27 k[31] |= 0x40 28 k[0] &= 0xF8 29 } 30 31 /* Key-pair generation 32 * P [out] your public key 33 * s [out] your private key for signing, may be nil if you don't care 34 * k [out] your private key for key agreement 35 * k [in] 32 random bytes 36 * 37 * WARNING: if s is not NULL, this function has data-dependent timing */ 38 func keygen(P, s, k []byte) { 39 clamp(k) 40 core(P, s, k, nil) 41 } 42 43 /* Key agreement 44 * Z [out] shared secret (needs hashing before use) 45 * k [in] your private key for key agreement 46 * P [in] peer's public key 47 */ 48 func curve(Z, k, P []byte) { 49 core(Z, nil, k, P) 50 } 51 52 /* P = kG and s = sign(P)/k */ 53 func core(Px, s, k, Gx []byte) { 54 dx := new(long10) 55 t1 := new(long10) 56 t2 := new(long10) 57 t3 := new(long10) 58 t4 := new(long10) 59 60 x := [2]*long10{new(long10), new(long10)} 61 z := [2]*long10{new(long10), new(long10)} 62 63 /* unpack the base */ 64 if Gx != nil { 65 dx.unpack(Gx) 66 67 } else { 68 dx.set(9) 69 } 70 71 /* 0G = point-at-infinity */ 72 x[0].set(1) 73 z[0].set(0) 74 75 /* 1G = G */ 76 x[1].cpy(dx) 77 z[1].set(1) 78 79 for i := 31; i >= 0; i-- { 80 for j := 7; j >= 0; j-- { 81 /* swap arguments depending on bit */ 82 uj := uint(j) 83 bit1 := (k[i] & 0xFF) >> uj & 1 84 bit0 := ^(k[i] & 0xFF) >> uj & 1 85 86 ax := x[bit0] 87 az := z[bit0] 88 bx := x[bit1] 89 bz := z[bit1] 90 91 /* a' = a + b */ 92 /* b' = 2 b */ 93 montPrep(t1, t2, ax, az) 94 montPrep(t3, t4, bx, bz) 95 montAdd(t1, t2, t3, t4, ax, az, dx) 96 montDbl(t1, t2, t3, t4, bx, bz) 97 } 98 } 99 100 t1.recip(z[0], false) 101 dx.mul(x[0], t1) 102 dx.pack(Px) 103 104 /* calculate s such that s abs(P) = G .. assumes G is std base point */ 105 if s != nil { 106 t1.xToY2(dx, t2) /* t1 = Py^2 */ 107 t3.recip(z[1], false) /* where Q=P+G ... */ 108 t2.mul(x[1], t3) /* t2 = Qx */ 109 t2.add(t2, dx) /* t2 = Qx + Px */ 110 t2[0] += 9 + 486662 /* t2 = Qx + Px + Gx + 486662 */ 111 dx[0] -= 9 /* dx = Px - Gx */ 112 t3.sqr(dx) /* t3 = (Px - Gx)^2 */ 113 dx.mul(t2, t3) /* dx = t2 (Px - Gx)^2 */ 114 dx.sub(dx, t1) /* dx = t2 (Px - Gx)^2 - Py^2 */ 115 dx[0] -= 39420360 /* dx = t2 (Px - Gx)^2 - Py^2 - Gy^2 */ 116 t1.mul(dx, baseR2y) /* t1 = -Py */ 117 if t1.isNegative() { /* sign is 1, so just copy */ 118 copy(s, k) 119 } else { /* sign is -1, so negate */ 120 mulaSmall(s, orderTimes8, 0, k, 32, -1) 121 } 122 123 /* reduce s mod q 124 * (is this needed? do it just in case, it's fast anyway) */ 125 //divmod((dstptr) t1, s, 32, order25519, 32); 126 127 /* take reciprocal of s mod q */ 128 temp1 := make([]byte, 32) 129 temp2 := make([]byte, 64) 130 temp3 := make([]byte, 64) 131 copy(temp1, order) 132 copy(s, egcd32(temp2, temp3, s, temp1)) 133 if (s[31] & 0x80) != 0 { 134 mulaSmall(s, s, 0, order, 32, 1) 135 } 136 } 137 } 138 139 /* deterministic EC-KCDSA 140 * 141 * s is the private key for signing 142 * P is the corresponding public key 143 * Z is the context data (signer public key or certificate, etc) 144 * 145 * signing: 146 * 147 * m = hash(Z, message) 148 * x = hash(m, s) 149 * keygen25519(Y, NULL, x); 150 * r = hash(Y); 151 * h = m XOR r 152 * sign25519(v, h, x, s); 153 * 154 * output (v,r) as the signature 155 * 156 * verification: 157 * 158 * m = hash(Z, message); 159 * h = m XOR r 160 * verify25519(Y, v, h, P) 161 * 162 * confirm r == hash(Y) 163 * 164 * It would seem to me that it would be simpler to have the signer directly do 165 * h = hash(m, Y) and send that to the recipient instead of r, who can verify 166 * the signature by checking h == hash(m, Y). If there are any problems with 167 * such a scheme, please let me know. 168 * 169 * Also, EC-KCDSA (like most DS algorithms) picks x random, which is a waste of 170 * perfectly good entropy, but does allow Y to be calculated in advance of (or 171 * parallel to) hashing the message. 172 */ 173 174 /* Signature generation primitive, calculates (x-h)s mod q 175 * v [out] signature value 176 * h [in] signature hash (of message, signature pub key, and context data) 177 * x [in] signature private key 178 * s [in] private key for signing 179 * returns true on success, false on failure (use different x or h) 180 */ 181 func sign(v, h, x, s []byte) bool { 182 // v = (x - h) s mod q 183 h1 := make([]byte, 32) 184 x1 := make([]byte, 32) 185 tmp1 := make([]byte, 64) 186 tmp2 := make([]byte, 64) 187 tmp3 := make([]byte, 32) 188 189 // Don't clobber the arguments, be nice! 190 copy(h1, h) 191 copy(x1, x) 192 193 // Reduce modulo group order 194 divmod(tmp3, h1, 32, order, 32) 195 divmod(tmp3, x1, 32, order, 32) 196 197 // v = x1 - h1 198 // If v is negative, add the group order to it to become positive. 199 // If v was already positive we don't have to worry about overflow 200 // when adding the order because v < ORDER and 2*ORDER < 2^256 201 mulaSmall(v, x1, 0, h1, 32, -1) 202 mulaSmall(v, v, 0, order, 32, 1) 203 204 // tmp1 = (x-h)*s mod q 205 mula32(tmp1, v, s, 32, 1) 206 divmod(tmp2, tmp1, 64, order, 32) 207 w := byte(0) 208 for i := 0; i < 32; i++ { 209 v[i] = tmp1[i] 210 w |= tmp1[i] 211 } 212 return w != 0 213 } 214 215 /* Signature verification primitive, calculates Y = vP + hG 216 * Y [out] signature public key 217 * v [in] signature value 218 * h [in] signature hash 219 * P [in] public key 220 */ 221 func verify(Y, v, h, P []byte) { 222 /* Y = v abs(P) + h G */ 223 d := make([]byte, 32) 224 p := [2]*long10{new(long10), new(long10)} 225 s := [2]*long10{new(long10), new(long10)} 226 yx := [3]*long10{new(long10), new(long10), new(long10)} 227 yz := [3]*long10{new(long10), new(long10), new(long10)} 228 t1 := [3]*long10{new(long10), new(long10), new(long10)} 229 t2 := [3]*long10{new(long10), new(long10), new(long10)} 230 231 /* set p[0] to G and p[1] to P */ 232 233 p[0].set(9) 234 p[1].unpack(P) 235 236 /* set s[0] to P+G and s[1] to P-G */ 237 238 /* s[0] = (Py^2 + Gy^2 - 2 Py Gy)/(Px - Gx)^2 - Px - Gx - 486662 */ 239 /* s[1] = (Py^2 + Gy^2 + 2 Py Gy)/(Px - Gx)^2 - Px - Gx - 486662 */ 240 241 t2[0].xToY2(p[1], t1[0]) /* t2[0] = Py^2 */ 242 t1[0].sqrt(t2[0]) /* t1[0] = Py or -Py */ 243 j := 0 244 if t1[0].isNegative() { 245 j = 1 246 } 247 t2[0][0] += 39420360 /* t2[0] = Py^2 + Gy^2 */ 248 t2[1].mul(base2y, t1[0]) /* t2[1] = 2 Py Gy or -2 Py Gy */ 249 t1[j].sub(t2[0], t2[1]) /* t1[0] = Py^2 + Gy^2 - 2 Py Gy */ 250 t1[1-j].add(t2[0], t2[1]) /* t1[1] = Py^2 + Gy^2 + 2 Py Gy */ 251 t2[0].cpy(p[1]) /* t2[0] = Px */ 252 t2[0][0] -= 9 /* t2[0] = Px - Gx */ 253 t2[1].sqr(t2[0]) /* t2[1] = (Px - Gx)^2 */ 254 t2[0].recip(t2[1], false) /* t2[0] = 1/(Px - Gx)^2 */ 255 s[0].mul(t1[0], t2[0]) /* s[0] = t1[0]/(Px - Gx)^2 */ 256 s[0].sub(s[0], p[1]) /* s[0] = t1[0]/(Px - Gx)^2 - Px */ 257 s[0][0] -= 9 + 486662 /* s[0] = X(P+G) */ 258 s[1].mul(t1[1], t2[0]) /* s[1] = t1[1]/(Px - Gx)^2 */ 259 s[1].sub(s[1], p[1]) /* s[1] = t1[1]/(Px - Gx)^2 - Px */ 260 s[1][0] -= 9 + 486662 /* s[1] = X(P-G) */ 261 s[0].mulSmall(s[0], 1) /* reduce s[0] */ 262 s[1].mulSmall(s[1], 1) /* reduce s[1] */ 263 264 /* prepare the chain */ 265 var vi, hi, di, nvh int 266 for i := 0; i < 32; i++ { 267 vi = (vi >> 8) ^ int(v[i]&0xFF) ^ (int(v[i]&0xFF) << 1) 268 hi = (hi >> 8) ^ int(h[i]&0xFF) ^ (int(h[i]&0xFF) << 1) 269 nvh = ^(vi ^ hi) 270 di = (nvh & ((di & 0x80) >> 7)) ^ vi 271 di ^= nvh & ((di & 0x01) << 1) 272 di ^= nvh & ((di & 0x02) << 1) 273 di ^= nvh & ((di & 0x04) << 1) 274 di ^= nvh & ((di & 0x08) << 1) 275 di ^= nvh & ((di & 0x10) << 1) 276 di ^= nvh & ((di & 0x20) << 1) 277 di ^= nvh & ((di & 0x40) << 1) 278 d[i] = byte(di) 279 } 280 281 di = ((nvh & ((di & 0x80) << 1)) ^ vi) >> 8 282 283 /* initialize state */ 284 yx[0].set(1) 285 yx[1].cpy(p[di]) 286 yx[2].cpy(s[0]) 287 yz[0].set(0) 288 yz[1].set(1) 289 yz[2].set(1) 290 291 /* y[0] is (even)P + (even)G 292 * y[1] is (even)P + (odd)G if current d-bit is 0 293 * y[1] is (odd)P + (even)G if current d-bit is 1 294 * y[2] is (odd)P + (odd)G 295 */ 296 297 vi = 0 298 hi = 0 299 300 /* and go for it! */ 301 for i := 31; i >= 0; i-- { 302 vi = (vi << 8) | int(v[i]&0xFF) 303 hi = (hi << 8) | int(h[i]&0xFF) 304 di = (di << 8) | int(d[i]&0xFF) 305 for j = 7; j >= 0; j-- { 306 montPrep(t1[0], t2[0], yx[0], yz[0]) 307 montPrep(t1[1], t2[1], yx[1], yz[1]) 308 montPrep(t1[2], t2[2], yx[2], yz[2]) 309 310 uj := uint(j) 311 k := ((vi ^ vi>>1) >> uj & 1) + ((hi ^ hi>>1) >> uj & 1) 312 montDbl(yx[2], yz[2], t1[k], t2[k], yx[0], yz[0]) 313 k = (di >> uj & 2) ^ ((di >> uj & 1) << 1) 314 montAdd(t1[1], t2[1], t1[k], t2[k], yx[1], yz[1], p[di>>uj&1]) 315 montAdd(t1[2], t2[2], t1[0], t2[0], yx[2], yz[2], s[((vi^hi)>>uj&2)>>1]) 316 } 317 } 318 319 k := (vi & 1) + (hi & 1) 320 t1[0].recip(yz[k], false) 321 t1[1].mul(yx[k], t1[0]) 322 t1[1].pack(Y) 323 } 324 325 func isCanonicalSignature(v []byte) bool { 326 if len(v) < 32 { 327 return false 328 } 329 vCopy := append(v[:0:0], v[:32]...) 330 divmod(make([]byte, 32), vCopy, 32, order, 32) 331 return bytes.Equal(vCopy, v[:32]) 332 } 333 334 func isCanonicalPublicKey(P []byte) bool { 335 if len(P) != 32 { 336 return false 337 } 338 339 rawP := new(long10) 340 rawP.unpack(P) 341 PCopy := rawP.pack(nil) 342 return bytes.Equal(PCopy, P) 343 }