1 module secp256k1; 2 3 import std.stdio; 4 import std.exception : enforce; 5 import std.conv : to; 6 7 import core.stdc.stdlib : free; 8 9 import deimos.openssl.ec; 10 import deimos.openssl.evp; 11 import deimos.openssl.pem; 12 import deimos.openssl.ecdsa; 13 import deimos.openssl.bn; 14 import deimos.openssl.obj_mac : NID_secp256k1; 15 16 alias bytes = ubyte[]; 17 unittest 18 { 19 writeln("Elliptic Curve example"); 20 auto pk = new ubyte[32]; 21 pk[0 .. $] = [ 22 50, 93, 176, 197, 179, 11, 107, 161, 16, 47, 114, 191, 181, 146, 4, 60, 23 66, 29, 253, 65, 237, 252, 116, 78, 218, 69, 204, 32, 73, 168, 217, 121 24 ]; 25 auto ec = new secp256k1(pk); 26 ec.writeln; 27 ec.sign!string("abababa").writeln; 28 } 29 30 class secp256k1 31 { 32 EC_KEY* ec_key; 33 34 this(ubyte[] pk = null) 35 { 36 ec_key = EC_KEY_new_by_curve_name(NID_secp256k1); 37 if (pk == null) 38 { 39 EC_KEY_generate_key(ec_key); 40 } 41 else 42 { 43 auto bn_pk = BN_bin2bn(pk.ptr, cast(int) pk.length, null); 44 EC_KEY_set_private_key(ec_key, bn_pk); 45 auto group = EC_KEY_get0_group(ec_key); 46 auto pub_key = EC_POINT_new(group); 47 auto ctx = BN_CTX_new(); 48 scope (exit) 49 { 50 BN_free(bn_pk); 51 BN_CTX_free(ctx); 52 EC_POINT_free(pub_key); 53 } 54 EC_POINT_mul(group, pub_key, bn_pk, null, null, ctx); 55 EC_KEY_set_public_key(ec_key, pub_key); 56 } 57 } 58 59 auto sign(Result, Input)(Input data) 60 { 61 ubyte[] _data = cast(ubyte[]) data.dup; 62 auto sig = ECDSA_do_sign(_data.ptr, cast(int) _data.length, ec_key); 63 assert(ECDSA_do_verify(_data.ptr, cast(int) _data.length, sig, ec_key), "Check signature"); 64 static if (is(Result == string)) 65 { 66 auto rptr = BN_bn2hex(sig.r); 67 auto sptr = BN_bn2hex(sig.s); 68 auto result = rptr.to!string ~ BN_bn2hex(sig.s).to!string; 69 scope (exit) 70 { 71 free(rptr); 72 free(sptr); 73 } 74 } 75 else 76 { 77 ubyte[32] r; 78 ubyte[32] s; 79 BN_bn2bin(sig.r, r.ptr); 80 BN_bn2bin(sig.s, s.ptr); 81 auto result = r[] ~ s[]; 82 } 83 ECDSA_SIG_free(sig); 84 return result; 85 } 86 87 override string toString() 88 { 89 auto pkBN = EC_KEY_get0_private_key(ec_key); 90 auto cptr = BN_bn2hex(pkBN); 91 ubyte[32] pkBytes; 92 BN_bn2bin(pkBN, pkBytes.ptr); 93 string result = cptr.to!string ~ pkBytes.to!string ~ " Can sign: " ~ EC_KEY_check_key(ec_key) 94 .to!string; 95 free(cptr); 96 return result; 97 } 98 99 ~this() 100 { 101 EC_KEY_free(ec_key); 102 } 103 104 int parity() 105 { 106 auto point = EC_KEY_get0_public_key(ec_key); 107 auto group = EC_KEY_get0_group(ec_key); 108 auto x = BN_new(), y = BN_new(); 109 auto ctx = BN_CTX_new(); 110 scope (exit) 111 { 112 BN_CTX_free(ctx); 113 BN_free(x); 114 BN_free(y); 115 } 116 EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx); 117 return BN_is_odd(y); 118 } 119 }