├── Makefile ├── bench.cpp ├── ecdsa.cpp ├── ecdsa.h ├── ecmult.cpp ├── ecmult.h ├── field.cpp ├── field.h ├── group.cpp ├── group.h ├── num.cpp ├── num.h ├── num_builtin.h ├── num_gmp.cpp ├── num_gmp.h ├── num_openssl.cpp ├── num_openssl.h ├── secp256k1.cpp ├── secp256k1.h └── tests.cpp /Makefile: -------------------------------------------------------------------------------- 1 | FLAGS_COMMON:=-Wall 2 | FLAGS_PROD:=-DNDEBUG -g0 -O3 -march=native 3 | FLAGS_DEBUG:=-DVERIFY_MAGNITUDE -ggdb3 -O1 4 | FLAGS_TEST:=-DVERIFY_MAGNITUDE -ggdb3 -O3 -march=native 5 | 6 | SECP256K1_FILES := num.h field.h group.h ecmult.h ecdsa.h \ 7 | num.cpp field.cpp group.cpp ecmult.cpp ecdsa.cpp \ 8 | 9 | ifndef CONF 10 | CONF := gmp 11 | endif 12 | 13 | ifeq ($(CONF), openssl) 14 | FLAGS_CONF:=-DUSE_NUM_OPENSSL -DUSE_FIELDINVERSE_BUILTIN 15 | LIBS:=-lcrypto 16 | SECP256K1_FILES := $(SECP256K1_FILES) num_openssl.h num_openssl.cpp 17 | else 18 | ifeq ($(CONF), gmp) 19 | FLAGS_CONF:=-DUSE_NUM_GMP 20 | LIBS:=-lgmp 21 | SECP256K1_FILES := $(SECP256K1_FILES) num_gmp.h num_gmp.cpp 22 | endif 23 | endif 24 | 25 | all: *.cpp *.h 26 | +make CONF=openssl all-openssl 27 | +make CONF=gmp all-gmp 28 | 29 | clean: 30 | +make CONF=openssl clean-openssl 31 | +make CONF=gmp clean-gmp 32 | 33 | bench-any: bench-$(CONF) 34 | tests-any: tests-$(CONF) 35 | 36 | all-$(CONF): bench-$(CONF) tests-$(CONF) 37 | 38 | clean-$(CONF): 39 | rm -f bench-$(CONF) tests-$(CONF) obj/secp256k1-$(CONF).o 40 | 41 | obj/secp256k1-$(CONF).o: $(SECP256K1_FILES) 42 | $(CXX) $(FLAGS_COMMON) $(FLAGS_PROD) $(FLAGS_CONF) secp256k1.cpp -c -o obj/secp256k1-$(CONF).o 43 | 44 | bench-$(CONF): obj/secp256k1-$(CONF).o bench.cpp 45 | $(CXX) $(FLAGS_COMMON) $(FLAGS_PROD) $(FLAGS_CONF) obj/secp256k1-$(CONF).o bench.cpp $(LIBS) -o bench-$(CONF) 46 | 47 | tests-$(CONF): $(SECP256K1_FILES) tests.cpp 48 | $(CXX) $(FLAGS_COMMON) $(FLAGS_TEST) $(FLAGS_CONF) tests.cpp $(LIBS) -o tests-$(CONF) 49 | -------------------------------------------------------------------------------- /bench.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "num.h" 4 | #include "field.h" 5 | #include "group.h" 6 | #include "ecmult.h" 7 | #include "ecdsa.h" 8 | 9 | using namespace secp256k1; 10 | 11 | int main() { 12 | FieldElem x; 13 | const Number &order = GetGroupConst().order; 14 | Number r, s, m; 15 | Signature sig; 16 | x.SetHex("a357ae915c4a65281309edf20504740f0eb3343990216b4f81063cb65f2f7e0f"); 17 | int cnt = 0; 18 | int good = 0; 19 | for (int i=0; i<1000000; i++) { 20 | r.SetPseudoRand(order); 21 | s.SetPseudoRand(order); 22 | m.SetPseudoRand(order); 23 | sig.SetRS(r,s); 24 | GroupElemJac pubkey; pubkey.SetCompressed(x, true); 25 | if (pubkey.IsValid()) { 26 | cnt++; 27 | good += sig.Verify(pubkey, m); 28 | } 29 | } 30 | printf("%i/%i\n", good, cnt); 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /ecdsa.cpp: -------------------------------------------------------------------------------- 1 | #include "num.h" 2 | #include "field.h" 3 | #include "group.h" 4 | #include "ecmult.h" 5 | #include "ecdsa.h" 6 | 7 | namespace secp256k1 { 8 | 9 | bool ParsePubKey(GroupElemJac &elem, const unsigned char *pub, int size) { 10 | if (size == 33 && (pub[0] == 0x02 || pub[0] == 0x03)) { 11 | FieldElem x; 12 | x.SetBytes(pub+1); 13 | elem.SetCompressed(x, pub[0] == 0x03); 14 | } else if (size == 65 && (pub[0] == 0x04 || pub[0] == 0x06 || pub[0] == 0x07)) { 15 | FieldElem x,y; 16 | x.SetBytes(pub+1); 17 | y.SetBytes(pub+33); 18 | elem = GroupElem(x,y); 19 | if ((pub[0] == 0x06 || pub[0] == 0x07) && y.IsOdd() != (pub[0] == 0x07)) 20 | return false; 21 | } else { 22 | return false; 23 | } 24 | return elem.IsValid(); 25 | } 26 | 27 | bool Signature::Parse(const unsigned char *sig, int size) { 28 | if (sig[0] != 0x30) return false; 29 | int lenr = sig[3]; 30 | if (5+lenr >= size) return false; 31 | int lens = sig[lenr+5]; 32 | if (sig[1] != lenr+lens+4) return false; 33 | if (lenr+lens+6 > size) return false; 34 | if (sig[2] != 0x02) return false; 35 | if (lenr == 0) return false; 36 | if (sig[lenr+4] != 0x02) return false; 37 | if (lens == 0) return false; 38 | r.SetBytes(sig+4, lenr); 39 | s.SetBytes(sig+6+lenr, lens); 40 | return true; 41 | } 42 | 43 | bool Signature::Serialize(unsigned char *sig, int *size) { 44 | int lenR = (r.GetBits() + 7)/8; 45 | if (lenR == 0 || r.CheckBit(lenR*8-1)) 46 | lenR++; 47 | int lenS = (s.GetBits() + 7)/8; 48 | if (lenS == 0 || s.CheckBit(lenS*8-1)) 49 | lenS++; 50 | if (*size < 6+lenS+lenR) 51 | return false; 52 | *size = 6 + lenS + lenR; 53 | sig[0] = 0x30; 54 | sig[1] = 4 + lenS + lenR; 55 | sig[2] = 0x02; 56 | sig[3] = lenR; 57 | r.GetBytes(sig+4, lenR); 58 | sig[4+lenR] = 0x02; 59 | sig[5+lenR] = lenS; 60 | s.GetBytes(sig+6, lenS); 61 | return true; 62 | } 63 | 64 | bool Signature::RecomputeR(Number &r2, const GroupElemJac &pubkey, const Number &message) const { 65 | const GroupConstants &c = GetGroupConst(); 66 | 67 | if (r.IsNeg() || s.IsNeg()) 68 | return false; 69 | if (r.IsZero() || s.IsZero()) 70 | return false; 71 | if (r.Compare(c.order) >= 0 || s.Compare(c.order) >= 0) 72 | return false; 73 | 74 | Number sn, u1, u2; 75 | sn.SetModInverse(s, c.order); 76 | u1.SetModMul(sn, message, c.order); 77 | u2.SetModMul(sn, r, c.order); 78 | GroupElemJac pr; ECMult(pr, pubkey, u2, u1); 79 | if (pr.IsInfinity()) 80 | return false; 81 | FieldElem xr; pr.GetX(xr); 82 | xr.Normalize(); 83 | unsigned char xrb[32]; xr.GetBytes(xrb); 84 | r2.SetBytes(xrb,32); r2.SetMod(r2,c.order); 85 | return true; 86 | } 87 | 88 | bool Signature::Verify(const GroupElemJac &pubkey, const Number &message) const { 89 | Number r2; 90 | if (!RecomputeR(r2, pubkey, message)) 91 | return false; 92 | return r2.Compare(r) == 0; 93 | } 94 | 95 | bool Signature::Sign(const Number &seckey, const Number &message, const Number &nonce) { 96 | const GroupConstants &c = GetGroupConst(); 97 | 98 | GroupElemJac rp; 99 | ECMultBase(rp, nonce); 100 | FieldElem rx; 101 | rp.GetX(rx); 102 | unsigned char b[32]; 103 | rx.Normalize(); 104 | rx.GetBytes(b); 105 | r.SetBytes(b, 32); 106 | r.SetMod(r, c.order); 107 | Number n; 108 | n.SetModMul(r, seckey, c.order); 109 | n.SetAdd(message, n); 110 | s.SetModInverse(nonce, c.order); 111 | s.SetModMul(s, n, c.order); 112 | if (s.IsZero()) 113 | return false; 114 | if (s.IsOdd()) 115 | s.SetSub(c.order, s); 116 | return true; 117 | } 118 | 119 | void Signature::SetRS(const Number &rin, const Number &sin) { 120 | r = rin; 121 | s = sin; 122 | } 123 | 124 | std::string Signature::ToString() const { 125 | return "(" + r.ToString() + "," + s.ToString() + ")"; 126 | } 127 | 128 | } 129 | -------------------------------------------------------------------------------- /ecdsa.h: -------------------------------------------------------------------------------- 1 | #ifndef _SECP256K1_ECDSA_ 2 | #define _SECP256K1_ECDSA_ 3 | 4 | namespace secp256k1 { 5 | 6 | class Signature { 7 | private: 8 | Number r,s; 9 | 10 | public: 11 | bool Parse(const unsigned char *sig, int size); 12 | bool Serialize(unsigned char *sig, int *size); 13 | bool RecomputeR(Number &r2, const GroupElemJac &pubkey, const Number &message) const; 14 | bool Verify(const GroupElemJac &pubkey, const Number &message) const; 15 | bool Sign(const Number &seckey, const Number &message, const Number &nonce); 16 | void SetRS(const Number &rin, const Number &sin); 17 | std::string ToString() const; 18 | }; 19 | 20 | } 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /ecmult.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "num.h" 5 | #include "group.h" 6 | #include "ecmult.h" 7 | 8 | // optimal for 128-bit and 256-bit exponents 9 | #define WINDOW_A 5 10 | 11 | // larger numbers may result in slightly better performance, at the cost of 12 | // exponentially larger precomputed tables. WINDOW_G == 13 results in 640 KiB. 13 | #define WINDOW_G 14 14 | 15 | namespace secp256k1 { 16 | 17 | template class WNAFPrecomp { 18 | private: 19 | G pre[1 << (W-2)]; 20 | 21 | public: 22 | WNAFPrecomp() {} 23 | 24 | void Build(const G &base) { 25 | pre[0] = base; 26 | GroupElemJac x(base); 27 | GroupElemJac d; d.SetDouble(x); 28 | for (int i=1; i<(1 << (W-2)); i++) { 29 | x.SetAdd(d,pre[i-1]); 30 | pre[i].SetJac(x); 31 | } 32 | } 33 | 34 | WNAFPrecomp(const G &base) { 35 | Build(base); 36 | } 37 | 38 | void Get(G &out, int exp) const { 39 | assert((exp & 1) == 1); 40 | assert(exp >= -((1 << (W-1)) - 1)); 41 | assert(exp <= ((1 << (W-1)) - 1)); 42 | if (exp > 0) { 43 | out = pre[(exp-1)/2]; 44 | } else { 45 | out.SetNeg(pre[(-exp-1)/2]); 46 | } 47 | } 48 | }; 49 | 50 | template class WNAF { 51 | private: 52 | int naf[B+1]; 53 | int used; 54 | 55 | void PushNAF(int num, int zeroes) { 56 | assert(used < B+1); 57 | for (int i=0; i= 0 && pos < used); 95 | return naf[pos]; 96 | } 97 | 98 | std::string ToString() { 99 | std::stringstream ss; 100 | ss << "("; 101 | for (int i=0; i wpg; 114 | WNAFPrecomp wpg128; 115 | GroupElem prec[64][16]; // prec[j][i] = 16^j * (i+1) * G 116 | GroupElem fin; // -(sum(prec[j][0], j=0..63)) 117 | 118 | ECMultConsts() { 119 | const GroupElem &g = GetGroupConst().g; 120 | GroupElemJac g128j(g); 121 | for (int i=0; i<128; i++) 122 | g128j.SetDouble(g128j); 123 | GroupElem g128; g128.SetJac(g128j); 124 | wpg.Build(g); 125 | wpg128.Build(g128); 126 | GroupElemJac gg(g); 127 | GroupElem ad(g); 128 | GroupElemJac fn; 129 | for (int j=0; j<64; j++) { 130 | prec[j][0].SetJac(gg); 131 | fn.SetAdd(fn, gg); 132 | for (int i=1; i<16; i++) { 133 | gg.SetAdd(gg, ad); 134 | prec[j][i].SetJac(gg); 135 | } 136 | ad = prec[j][15]; 137 | } 138 | fn.SetNeg(fn); 139 | fin.SetJac(fn); 140 | } 141 | }; 142 | 143 | const ECMultConsts &GetECMultConsts() { 144 | static const ECMultConsts ecmult_consts; 145 | return ecmult_consts; 146 | } 147 | 148 | void ECMultBase(GroupElemJac &out, const Number &gn) { 149 | Number n; n.SetNumber(gn); 150 | const ECMultConsts &c = GetECMultConsts(); 151 | out.SetAffine(c.prec[0][n.ShiftLowBits(4)]); 152 | for (int j=1; j<64; j++) { 153 | out.SetAdd(out, c.prec[j][n.ShiftLowBits(4)]); 154 | } 155 | out.SetAdd(out, c.fin); 156 | } 157 | 158 | void ECMult(GroupElemJac &out, const GroupElemJac &a, const Number &an, const Number &gn) { 159 | Number an1, an2; 160 | Number gn1, gn2; 161 | 162 | SplitExp(an, an1, an2); 163 | // printf("an=%s\n", an.ToString().c_str()); 164 | // printf("an1=%s\n", an1.ToString().c_str()); 165 | // printf("an2=%s\n", an2.ToString().c_str()); 166 | // printf("an1.len=%i\n", an1.GetBits()); 167 | // printf("an2.len=%i\n", an2.GetBits()); 168 | gn.SplitInto(128, gn1, gn2); 169 | 170 | WNAF<128> wa1(an1, WINDOW_A); 171 | WNAF<128> wa2(an2, WINDOW_A); 172 | WNAF<128> wg1(gn1, WINDOW_G); 173 | WNAF<128> wg2(gn2, WINDOW_G); 174 | GroupElemJac a2; a2.SetMulLambda(a); 175 | WNAFPrecomp wpa1(a); 176 | WNAFPrecomp wpa2(a2); 177 | const ECMultConsts &c = GetECMultConsts(); 178 | 179 | int size_a1 = wa1.GetSize(); 180 | int size_a2 = wa2.GetSize(); 181 | int size_g1 = wg1.GetSize(); 182 | int size_g2 = wg2.GetSize(); 183 | int size = std::max(std::max(size_a1, size_a2), std::max(size_g1, size_g2)); 184 | 185 | out = GroupElemJac(); 186 | GroupElemJac tmpj; 187 | GroupElem tmpa; 188 | 189 | for (int i=size-1; i>=0; i--) { 190 | out.SetDouble(out); 191 | int nw; 192 | if (i < size_a1 && (nw = wa1.Get(i))) { 193 | wpa1.Get(tmpj, nw); 194 | out.SetAdd(out, tmpj); 195 | } 196 | if (i < size_a2 && (nw = wa2.Get(i))) { 197 | wpa2.Get(tmpj, nw); 198 | out.SetAdd(out, tmpj); 199 | } 200 | if (i < size_g1 && (nw = wg1.Get(i))) { 201 | c.wpg.Get(tmpa, nw); 202 | out.SetAdd(out, tmpa); 203 | } 204 | if (i < size_g2 && (nw = wg2.Get(i))) { 205 | c.wpg128.Get(tmpa, nw); 206 | out.SetAdd(out, tmpa); 207 | } 208 | } 209 | } 210 | 211 | } 212 | -------------------------------------------------------------------------------- /ecmult.h: -------------------------------------------------------------------------------- 1 | #ifndef _SECP256K1_ECMULT_ 2 | #define _SECP256K1_ECMULT_ 3 | 4 | #include "group.h" 5 | #include "num.h" 6 | 7 | namespace secp256k1 { 8 | 9 | void ECMultBase(GroupElemJac &out, const Number &gn); 10 | void ECMult(GroupElemJac &out, const GroupElemJac &a, const Number &an, const Number &gn); 11 | 12 | } 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /field.cpp: -------------------------------------------------------------------------------- 1 | using namespace std; 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "num.h" 8 | #include "field.h" 9 | 10 | // #define VERIFY_MAGNITUDE 1 11 | 12 | namespace secp256k1 { 13 | 14 | /** Implements arithmetic modulo FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F, 15 | * represented as 5 uint64_t's in base 2^52. The values are allowed to contain >52 each. In particular, 16 | * each FieldElem has a 'magnitude' associated with it. Internally, a magnitude M means each element 17 | * is at most M*(2^53-1), except the most significant one, which is limited to M*(2^49-1). All operations 18 | * accept any input with magnitude at most M, and have different rules for propagating magnitude to their 19 | * output. 20 | */ 21 | 22 | FieldElem::FieldElem(int x) { 23 | n[0] = x; 24 | n[1] = n[2] = n[3] = n[4] = 0; 25 | #ifdef VERIFY_MAGNITUDE 26 | magnitude = 1; 27 | normalized = true; 28 | #endif 29 | } 30 | 31 | FieldElem::FieldElem(const unsigned char *b32) { 32 | SetBytes(b32); 33 | } 34 | 35 | void FieldElem::Normalize() { 36 | uint64_t c; 37 | c = n[0]; 38 | uint64_t t0 = c & 0xFFFFFFFFFFFFFULL; 39 | c = (c >> 52) + n[1]; 40 | uint64_t t1 = c & 0xFFFFFFFFFFFFFULL; 41 | c = (c >> 52) + n[2]; 42 | uint64_t t2 = c & 0xFFFFFFFFFFFFFULL; 43 | c = (c >> 52) + n[3]; 44 | uint64_t t3 = c & 0xFFFFFFFFFFFFFULL; 45 | c = (c >> 52) + n[4]; 46 | uint64_t t4 = c & 0x0FFFFFFFFFFFFULL; 47 | c >>= 48; 48 | 49 | // The following code will not modify the t's if c is initially 0. 50 | c = c * 0x1000003D1ULL + t0; 51 | t0 = c & 0xFFFFFFFFFFFFFULL; 52 | c = (c >> 52) + t1; 53 | t1 = c & 0xFFFFFFFFFFFFFULL; 54 | c = (c >> 52) + t2; 55 | t2 = c & 0xFFFFFFFFFFFFFULL; 56 | c = (c >> 52) + t3; 57 | t3 = c & 0xFFFFFFFFFFFFFULL; 58 | c = (c >> 52) + t4; 59 | t4 = c & 0x0FFFFFFFFFFFFULL; 60 | 61 | // Replace n's with t's if one of the n's overflows. 62 | // If none of the n's overflow to begin with, the t's will just be the n's already and 63 | // we effectively ignore the results of the previous computations. 64 | n[0] = t0; n[1] = t1; n[2] = t2; n[3] = t3; n[4] = t4; 65 | 66 | // Subtract p if result >= p 67 | uint64_t mask = (uint64_t)~(-(int64_t)(n[4] == 0xFFFFFFFFFFFFULL && n[3] == 0xFFFFFFFFFFFFFULL && n[2] == 0xFFFFFFFFFFFFFULL && n[1] == 0xFFFFFFFFFFFFFULL && n[0] >= 0xFFFFEFFFFFC2FULL)); 68 | n[4] &= mask; 69 | n[3] &= mask; 70 | n[2] &= mask; 71 | n[1] &= mask; 72 | n[0] -= (~mask & 0xFFFFEFFFFFC2FULL); 73 | 74 | #ifdef VERIFY_MAGNITUDE 75 | magnitude = 1; 76 | normalized = true; 77 | #endif 78 | } 79 | 80 | bool inline FieldElem::IsZero() const { 81 | #ifdef VERIFY_MAGNITUDE 82 | assert(normalized); 83 | #endif 84 | return (n[0] == 0 && n[1] == 0 && n[2] == 0 && n[3] == 0 && n[4] == 0); 85 | } 86 | 87 | bool inline operator==(const FieldElem &a, const FieldElem &b) { 88 | #ifdef VERIFY_MAGNITUDE 89 | assert(a.normalized); 90 | assert(b.normalized); 91 | #endif 92 | return (a.n[0] == b.n[0] && a.n[1] == b.n[1] && a.n[2] == b.n[2] && a.n[3] == b.n[3] && a.n[4] == b.n[4]); 93 | } 94 | 95 | void FieldElem::GetBytes(unsigned char *o) { 96 | #ifdef VERIFY_MAGNITUDE 97 | assert(normalized); 98 | #endif 99 | for (int i=0; i<32; i++) { 100 | int c = 0; 101 | for (int j=0; j<2; j++) { 102 | int limb = (8*i+4*j)/52; 103 | int shift = (8*i+4*j)%52; 104 | c |= ((n[limb] >> shift) & 0xF) << (4 * j); 105 | } 106 | o[31-i] = c; 107 | } 108 | } 109 | 110 | void FieldElem::SetBytes(const unsigned char *in) { 111 | n[0] = n[1] = n[2] = n[3] = n[4] = 0; 112 | for (int i=0; i<32; i++) { 113 | for (int j=0; j<2; j++) { 114 | int limb = (8*i+4*j)/52; 115 | int shift = (8*i+4*j)%52; 116 | n[limb] |= (uint64_t)((in[31-i] >> (4*j)) & 0xF) << shift; 117 | } 118 | } 119 | #ifdef VERIFY_MAGNITUDE 120 | magnitude = 1; 121 | normalized = true; 122 | #endif 123 | } 124 | 125 | void inline FieldElem::SetNeg(const FieldElem &a, int magnitudeIn) { 126 | #ifdef VERIFY_MAGNITUDE 127 | assert(a.magnitude <= magnitudeIn); 128 | magnitude = magnitudeIn + 1; 129 | normalized = false; 130 | #endif 131 | n[0] = 0xFFFFEFFFFFC2FULL * (magnitudeIn + 1) - a.n[0]; 132 | n[1] = 0xFFFFFFFFFFFFFULL * (magnitudeIn + 1) - a.n[1]; 133 | n[2] = 0xFFFFFFFFFFFFFULL * (magnitudeIn + 1) - a.n[2]; 134 | n[3] = 0xFFFFFFFFFFFFFULL * (magnitudeIn + 1) - a.n[3]; 135 | n[4] = 0x0FFFFFFFFFFFFULL * (magnitudeIn + 1) - a.n[4]; 136 | } 137 | 138 | void inline FieldElem::operator*=(int v) { 139 | #ifdef VERIFY_MAGNITUDE 140 | magnitude *= v; 141 | normalized = false; 142 | #endif 143 | n[0] *= v; 144 | n[1] *= v; 145 | n[2] *= v; 146 | n[3] *= v; 147 | n[4] *= v; 148 | } 149 | 150 | void inline FieldElem::operator+=(const FieldElem &a) { 151 | #ifdef VERIFY_MAGNITUDE 152 | magnitude += a.magnitude; 153 | normalized = false; 154 | #endif 155 | n[0] += a.n[0]; 156 | n[1] += a.n[1]; 157 | n[2] += a.n[2]; 158 | n[3] += a.n[3]; 159 | n[4] += a.n[4]; 160 | } 161 | 162 | void FieldElem::SetMult(const FieldElem &a, const FieldElem &b) { 163 | #ifdef VERIFY_MAGNITUDE 164 | assert(a.magnitude <= 8); 165 | assert(b.magnitude <= 8); 166 | #endif 167 | __int128 c = (__int128)a.n[0] * b.n[0]; 168 | uint64_t t0 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0FFFFFFFFFFFFFE0 169 | c = c + (__int128)a.n[0] * b.n[1] + 170 | (__int128)a.n[1] * b.n[0]; 171 | uint64_t t1 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 20000000000000BF 172 | c = c + (__int128)a.n[0] * b.n[2] + 173 | (__int128)a.n[1] * b.n[1] + 174 | (__int128)a.n[2] * b.n[0]; 175 | uint64_t t2 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 30000000000001A0 176 | c = c + (__int128)a.n[0] * b.n[3] + 177 | (__int128)a.n[1] * b.n[2] + 178 | (__int128)a.n[2] * b.n[1] + 179 | (__int128)a.n[3] * b.n[0]; 180 | uint64_t t3 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 4000000000000280 181 | c = c + (__int128)a.n[0] * b.n[4] + 182 | (__int128)a.n[1] * b.n[3] + 183 | (__int128)a.n[2] * b.n[2] + 184 | (__int128)a.n[3] * b.n[1] + 185 | (__int128)a.n[4] * b.n[0]; 186 | uint64_t t4 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 320000000000037E 187 | c = c + (__int128)a.n[1] * b.n[4] + 188 | (__int128)a.n[2] * b.n[3] + 189 | (__int128)a.n[3] * b.n[2] + 190 | (__int128)a.n[4] * b.n[1]; 191 | uint64_t t5 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 22000000000002BE 192 | c = c + (__int128)a.n[2] * b.n[4] + 193 | (__int128)a.n[3] * b.n[3] + 194 | (__int128)a.n[4] * b.n[2]; 195 | uint64_t t6 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 12000000000001DE 196 | c = c + (__int128)a.n[3] * b.n[4] + 197 | (__int128)a.n[4] * b.n[3]; 198 | uint64_t t7 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 02000000000000FE 199 | c = c + (__int128)a.n[4] * b.n[4]; 200 | uint64_t t8 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 001000000000001E 201 | uint64_t t9 = c; 202 | c = t0 + (__int128)t5 * 0x1000003D10ULL; 203 | 204 | t0 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10 205 | c = c + t1 + (__int128)t6 * 0x1000003D10ULL; 206 | t1 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10 207 | c = c + t2 + (__int128)t7 * 0x1000003D10ULL; 208 | n[2] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10 209 | c = c + t3 + (__int128)t8 * 0x1000003D10ULL; 210 | n[3] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10 211 | c = c + t4 + (__int128)t9 * 0x1000003D10ULL; 212 | n[4] = c & 0x0FFFFFFFFFFFFULL; c = c >> 48; // c max 000001000003D110 213 | c = t0 + (__int128)c * 0x1000003D1ULL; 214 | n[0] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 1000008 215 | n[1] = t1 + c; 216 | #ifdef VERIFY_MAGNITUDE 217 | magnitude = 1; 218 | normalized = false; 219 | #endif 220 | } 221 | 222 | void FieldElem::SetSquare(const FieldElem &a) { 223 | #ifdef VERIFY_MAGNITUDE 224 | assert(a.magnitude <= 8); 225 | #endif 226 | __int128 c = (__int128)a.n[0] * a.n[0]; 227 | uint64_t t0 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0FFFFFFFFFFFFFE0 228 | c = c + (__int128)(a.n[0]*2) * a.n[1]; 229 | uint64_t t1 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 20000000000000BF 230 | c = c + (__int128)(a.n[0]*2) * a.n[2] + 231 | (__int128)a.n[1] * a.n[1]; 232 | uint64_t t2 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 30000000000001A0 233 | c = c + (__int128)(a.n[0]*2) * a.n[3] + 234 | (__int128)(a.n[1]*2) * a.n[2]; 235 | uint64_t t3 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 4000000000000280 236 | c = c + (__int128)(a.n[0]*2) * a.n[4] + 237 | (__int128)(a.n[1]*2) * a.n[3] + 238 | (__int128)a.n[2] * a.n[2]; 239 | uint64_t t4 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 320000000000037E 240 | c = c + (__int128)(a.n[1]*2) * a.n[4] + 241 | (__int128)(a.n[2]*2) * a.n[3]; 242 | uint64_t t5 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 22000000000002BE 243 | c = c + (__int128)(a.n[2]*2) * a.n[4] + 244 | (__int128)a.n[3] * a.n[3]; 245 | uint64_t t6 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 12000000000001DE 246 | c = c + (__int128)(a.n[3]*2) * a.n[4]; 247 | uint64_t t7 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 02000000000000FE 248 | c = c + (__int128)a.n[4] * a.n[4]; 249 | uint64_t t8 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 001000000000001E 250 | uint64_t t9 = c; 251 | c = t0 + (__int128)t5 * 0x1000003D10ULL; 252 | t0 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10 253 | c = c + t1 + (__int128)t6 * 0x1000003D10ULL; 254 | t1 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10 255 | c = c + t2 + (__int128)t7 * 0x1000003D10ULL; 256 | n[2] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10 257 | c = c + t3 + (__int128)t8 * 0x1000003D10ULL; 258 | n[3] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10 259 | c = c + t4 + (__int128)t9 * 0x1000003D10ULL; 260 | n[4] = c & 0x0FFFFFFFFFFFFULL; c = c >> 48; // c max 000001000003D110 261 | c = t0 + (__int128)c * 0x1000003D1ULL; 262 | n[0] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 1000008 263 | n[1] = t1 + c; 264 | #ifdef VERIFY_MAGNITUDE 265 | assert(a.magnitude <= 8); 266 | normalized = false; 267 | #endif 268 | } 269 | 270 | void FieldElem::SetSquareRoot(const FieldElem &a) { 271 | // calculate a^p, with p={15,780,1022,1023} 272 | FieldElem a2; a2.SetSquare(a); 273 | FieldElem a3; a3.SetMult(a2,a); 274 | FieldElem a6; a6.SetSquare(a3); 275 | FieldElem a12; a12.SetSquare(a6); 276 | FieldElem a15; a15.SetMult(a12,a3); 277 | FieldElem a30; a30.SetSquare(a15); 278 | FieldElem a60; a60.SetSquare(a30); 279 | FieldElem a120; a120.SetSquare(a60); 280 | FieldElem a240; a240.SetSquare(a120); 281 | FieldElem a255; a255.SetMult(a240,a15); 282 | FieldElem a510; a510.SetSquare(a255); 283 | FieldElem a750; a750.SetMult(a510,a240); 284 | FieldElem a780; a780.SetMult(a750,a30); 285 | FieldElem a1020; a1020.SetSquare(a510); 286 | FieldElem a1022; a1022.SetMult(a1020,a2); 287 | FieldElem a1023; a1023.SetMult(a1022,a); 288 | FieldElem x = a15; 289 | for (int i=0; i<21; i++) { 290 | for (int j=0; j<10; j++) x.SetSquare(x); 291 | x.SetMult(x,a1023); 292 | } 293 | for (int j=0; j<10; j++) x.SetSquare(x); 294 | x.SetMult(x,a1022); 295 | for (int i=0; i<2; i++) { 296 | for (int j=0; j<10; j++) x.SetSquare(x); 297 | x.SetMult(x,a1023); 298 | } 299 | for (int j=0; j<10; j++) x.SetSquare(x); 300 | SetMult(x,a780); 301 | } 302 | 303 | bool FieldElem::IsOdd() const { 304 | #ifdef VERIFY_MAGNITUDE 305 | assert(normalized); 306 | #endif 307 | return n[0] & 1; 308 | } 309 | 310 | std::string FieldElem::ToString() { 311 | unsigned char tmp[32]; 312 | Normalize(); 313 | GetBytes(tmp); 314 | std::string ret; 315 | for (int i=0; i<32; i++) { 316 | static const char *c = "0123456789ABCDEF"; 317 | ret += c[(tmp[i] >> 4) & 0xF]; 318 | ret += c[(tmp[i]) & 0xF]; 319 | } 320 | return ret; 321 | } 322 | 323 | void FieldElem::SetHex(const std::string &str) { 324 | unsigned char tmp[32] = {}; 325 | static const int cvt[256] = {0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, 326 | 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, 327 | 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, 328 | 0, 1, 2, 3, 4, 5, 6,7,8,9,0,0,0,0,0,0, 329 | 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0, 330 | 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, 331 | 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0, 332 | 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, 333 | 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, 334 | 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, 335 | 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, 336 | 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, 337 | 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, 338 | 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, 339 | 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, 340 | 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}; 341 | for (unsigned int i=0; i<32; i++) { 342 | if (str.length() > i*2) 343 | tmp[32 - str.length()/2 + i] = (cvt[(unsigned char)str[2*i]] << 4) + cvt[(unsigned char)str[2*i+1]]; 344 | } 345 | SetBytes(tmp); 346 | } 347 | 348 | static const unsigned char field_p_[] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 349 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 350 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 351 | 0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F}; 352 | 353 | FieldConstants::FieldConstants() : field_p(field_p_, sizeof(field_p_)) {} 354 | 355 | const FieldConstants &GetFieldConst() { 356 | static const FieldConstants field_const; 357 | return field_const; 358 | } 359 | 360 | // Nonbuiltin Field Inverse is not constant time. 361 | void FieldElem::SetInverse(FieldElem &a) { 362 | #if defined(USE_FIELDINVERSE_BUILTIN) 363 | // calculate a^p, with p={45,63,1019,1023} 364 | FieldElem a2; a2.SetSquare(a); 365 | FieldElem a3; a3.SetMult(a2,a); 366 | FieldElem a4; a4.SetSquare(a2); 367 | FieldElem a5; a5.SetMult(a4,a); 368 | FieldElem a10; a10.SetSquare(a5); 369 | FieldElem a11; a11.SetMult(a10,a); 370 | FieldElem a21; a21.SetMult(a11,a10); 371 | FieldElem a42; a42.SetSquare(a21); 372 | FieldElem a45; a45.SetMult(a42,a3); 373 | FieldElem a63; a63.SetMult(a42,a21); 374 | FieldElem a126; a126.SetSquare(a63); 375 | FieldElem a252; a252.SetSquare(a126); 376 | FieldElem a504; a504.SetSquare(a252); 377 | FieldElem a1008; a1008.SetSquare(a504); 378 | FieldElem a1019; a1019.SetMult(a1008,a11); 379 | FieldElem a1023; a1023.SetMult(a1019,a4); 380 | FieldElem x = a63; 381 | for (int i=0; i<21; i++) { 382 | for (int j=0; j<10; j++) x.SetSquare(x); 383 | x.SetMult(x,a1023); 384 | } 385 | for (int j=0; j<10; j++) x.SetSquare(x); 386 | x.SetMult(x,a1019); 387 | for (int i=0; i<2; i++) { 388 | for (int j=0; j<10; j++) x.SetSquare(x); 389 | x.SetMult(x,a1023); 390 | } 391 | for (int j=0; j<10; j++) x.SetSquare(x); 392 | SetMult(x,a45); 393 | #else 394 | unsigned char b[32]; 395 | a.Normalize(); 396 | a.GetBytes(b); 397 | { 398 | const Number &p = GetFieldConst().field_p; 399 | Number n; n.SetBytes(b, 32); 400 | n.SetModInverse(n, p); 401 | n.GetBytes(b, 32); 402 | } 403 | SetBytes(b); 404 | #endif 405 | } 406 | 407 | } 408 | -------------------------------------------------------------------------------- /field.h: -------------------------------------------------------------------------------- 1 | #ifndef _SECP256K1_FIELD_ 2 | #define _SECP256K1_FIELD_ 3 | 4 | using namespace std; 5 | 6 | #include 7 | #include 8 | 9 | #include "num.h" 10 | 11 | // #define VERIFY_MAGNITUDE 1 12 | 13 | namespace secp256k1 { 14 | 15 | /** Implements arithmetic modulo FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F, 16 | * represented as 5 uint64_t's in base 2^52. The values are allowed to contain >52 each. In particular, 17 | * each FieldElem has a 'magnitude' associated with it. Internally, a magnitude M means each element 18 | * is at most M*(2^53-1), except the most significant one, which is limited to M*(2^49-1). All operations 19 | * accept any input with magnitude at most M, and have different rules for propagating magnitude to their 20 | * output. 21 | */ 22 | class FieldElem { 23 | private: 24 | // X = sum(i=0..4, elem[i]*2^52) mod n 25 | uint64_t n[5]; 26 | #ifdef VERIFY_MAGNITUDE 27 | int magnitude; 28 | bool normalized; 29 | #endif 30 | 31 | public: 32 | 33 | /** Creates a constant field element. Magnitude=1 */ 34 | FieldElem(int x = 0); 35 | 36 | FieldElem(const unsigned char *b32); 37 | 38 | /** Normalizes the internal representation entries. Magnitude=1 */ 39 | void Normalize(); 40 | 41 | bool IsZero() const; 42 | 43 | bool friend operator==(const FieldElem &a, const FieldElem &b); 44 | 45 | /** extract as 32-byte big endian array */ 46 | void GetBytes(unsigned char *o); 47 | 48 | /** set value of 32-byte big endian array */ 49 | void SetBytes(const unsigned char *in); 50 | 51 | /** Set a FieldElem to be the negative of another. Increases magnitude by one. */ 52 | void SetNeg(const FieldElem &a, int magnitudeIn); 53 | 54 | /** Multiplies this FieldElem with an integer constant. Magnitude is multiplied by v */ 55 | void operator*=(int v); 56 | 57 | void operator+=(const FieldElem &a); 58 | 59 | /** Set this FieldElem to be the multiplication of two others. Magnitude=1 (variable time) */ 60 | void SetMult(const FieldElem &a, const FieldElem &b); 61 | 62 | /** Set this FieldElem to be the square of another. Magnitude=1 (variable time) */ 63 | void SetSquare(const FieldElem &a); 64 | 65 | /** Set this to be the (modular) square root of another FieldElem. Magnitude=1 */ 66 | void SetSquareRoot(const FieldElem &a); 67 | 68 | bool IsOdd() const; 69 | 70 | /** Set this to be the (modular) inverse of another FieldElem. Magnitude=1 (variable time) */ 71 | void SetInverse(FieldElem &a); 72 | 73 | std::string ToString(); 74 | 75 | void SetHex(const std::string &str); 76 | }; 77 | 78 | class FieldConstants { 79 | public: 80 | const Number field_p; 81 | 82 | FieldConstants(); 83 | }; 84 | 85 | const FieldConstants &GetFieldConst(); 86 | 87 | } 88 | 89 | #endif 90 | -------------------------------------------------------------------------------- /group.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "num.h" 4 | #include "field.h" 5 | #include "group.h" 6 | 7 | namespace secp256k1 { 8 | 9 | GroupElem::GroupElem() { 10 | fInfinity = true; 11 | } 12 | 13 | GroupElem::GroupElem(const FieldElem &xin, const FieldElem &yin) { 14 | fInfinity = false; 15 | x = xin; 16 | y = yin; 17 | } 18 | 19 | bool GroupElem::IsInfinity() const { 20 | return fInfinity; 21 | } 22 | 23 | void GroupElem::SetNeg(const GroupElem &p) { 24 | *this = p; 25 | y.Normalize(); 26 | y.SetNeg(y, 1); 27 | } 28 | 29 | void GroupElem::GetX(FieldElem &xout) { 30 | xout = x; 31 | } 32 | 33 | void GroupElem::GetY(FieldElem &yout) { 34 | yout = y; 35 | } 36 | 37 | std::string GroupElem::ToString() const { 38 | if (fInfinity) 39 | return "(inf)"; 40 | FieldElem xc = x, yc = y; 41 | return "(" + xc.ToString() + "," + yc.ToString() + ")"; 42 | } 43 | 44 | GroupElemJac::GroupElemJac() : GroupElem(), z(1) {} 45 | 46 | GroupElemJac::GroupElemJac(const FieldElem &xin, const FieldElem &yin) : GroupElem(xin,yin), z(1) {} 47 | 48 | GroupElemJac::GroupElemJac(const GroupElem &in) : GroupElem(in), z(1) {} 49 | 50 | void GroupElemJac::SetJac(const GroupElemJac &jac) { 51 | *this = jac; 52 | } 53 | 54 | void GroupElemJac::SetAffine(const GroupElem &aff) { 55 | fInfinity = aff.fInfinity; 56 | x = aff.x; 57 | y = aff.y; 58 | z = FieldElem(1); 59 | } 60 | 61 | bool GroupElemJac::IsValid() const { 62 | if (IsInfinity()) 63 | return false; 64 | // y^2 = x^3 + 7 65 | // (Y/Z^3)^2 = (X/Z^2)^3 + 7 66 | // Y^2 / Z^6 = X^3 / Z^6 + 7 67 | // Y^2 = X^3 + 7*Z^6 68 | FieldElem y2; y2.SetSquare(y); 69 | FieldElem x3; x3.SetSquare(x); x3.SetMult(x3,x); 70 | FieldElem z2; z2.SetSquare(z); 71 | FieldElem z6; z6.SetSquare(z2); z6.SetMult(z6,z2); 72 | z6 *= 7; 73 | x3 += z6; 74 | y2.Normalize(); 75 | x3.Normalize(); 76 | return y2 == x3; 77 | } 78 | 79 | void GroupElemJac::GetAffine(GroupElem &aff) { 80 | z.SetInverse(z); 81 | FieldElem z2; 82 | z2.SetSquare(z); 83 | FieldElem z3; 84 | z3.SetMult(z,z2); 85 | x.SetMult(x,z2); 86 | y.SetMult(y,z3); 87 | z = FieldElem(1); 88 | aff.fInfinity = fInfinity; 89 | aff.x = x; 90 | aff.y = y; 91 | } 92 | 93 | void GroupElemJac::GetX(FieldElem &xout) { 94 | FieldElem zi; 95 | zi.SetInverse(z); 96 | zi.SetSquare(zi); 97 | xout.SetMult(x, zi); 98 | } 99 | 100 | void GroupElemJac::GetY(FieldElem &yout) { 101 | FieldElem zi; 102 | zi.SetInverse(z); 103 | FieldElem zi3; zi3.SetSquare(zi); zi3.SetMult(zi, zi3); 104 | yout.SetMult(y, zi3); 105 | } 106 | 107 | bool GroupElemJac::IsInfinity() const { 108 | return fInfinity; 109 | } 110 | 111 | 112 | void GroupElemJac::SetNeg(const GroupElemJac &p) { 113 | *this = p; 114 | y.Normalize(); 115 | y.SetNeg(y, 1); 116 | } 117 | 118 | void GroupElemJac::SetCompressed(const FieldElem &xin, bool fOdd) { 119 | x = xin; 120 | FieldElem x2; x2.SetSquare(x); 121 | FieldElem x3; x3.SetMult(x,x2); 122 | fInfinity = false; 123 | FieldElem c(7); 124 | c += x3; 125 | y.SetSquareRoot(c); 126 | z = FieldElem(1); 127 | y.Normalize(); 128 | if (y.IsOdd() != fOdd) 129 | y.SetNeg(y,1); 130 | } 131 | 132 | void GroupElemJac::SetDouble(const GroupElemJac &p) { 133 | FieldElem t5 = p.y; 134 | t5.Normalize(); 135 | if (p.fInfinity || t5.IsZero()) { 136 | fInfinity = true; 137 | return; 138 | } 139 | 140 | FieldElem t1,t2,t3,t4; 141 | z.SetMult(t5,p.z); 142 | z *= 2; // Z' = 2*Y*Z (2) 143 | t1.SetSquare(p.x); 144 | t1 *= 3; // T1 = 3*X^2 (3) 145 | t2.SetSquare(t1); // T2 = 9*X^4 (1) 146 | t3.SetSquare(t5); 147 | t3 *= 2; // T3 = 2*Y^2 (2) 148 | t4.SetSquare(t3); 149 | t4 *= 2; // T4 = 8*Y^4 (2) 150 | t3.SetMult(p.x,t3); // T3 = 2*X*Y^2 (1) 151 | x = t3; 152 | x *= 4; // X' = 8*X*Y^2 (4) 153 | x.SetNeg(x,4); // X' = -8*X*Y^2 (5) 154 | x += t2; // X' = 9*X^4 - 8*X*Y^2 (6) 155 | t2.SetNeg(t2,1); // T2 = -9*X^4 (2) 156 | t3 *= 6; // T3 = 12*X*Y^2 (6) 157 | t3 += t2; // T3 = 12*X*Y^2 - 9*X^4 (8) 158 | y.SetMult(t1,t3); // Y' = 36*X^3*Y^2 - 27*X^6 (1) 159 | t2.SetNeg(t4,2); // T2 = -8*Y^4 (3) 160 | y += t2; // Y' = 36*X^3*Y^2 - 27*X^6 - 8*Y^4 (4) 161 | fInfinity = false; 162 | } 163 | 164 | void GroupElemJac::SetAdd(const GroupElemJac &p, const GroupElemJac &q) { 165 | if (p.fInfinity) { 166 | *this = q; 167 | return; 168 | } 169 | if (q.fInfinity) { 170 | *this = p; 171 | return; 172 | } 173 | fInfinity = false; 174 | const FieldElem &x1 = p.x, &y1 = p.y, &z1 = p.z, &x2 = q.x, &y2 = q.y, &z2 = q.z; 175 | FieldElem z22; z22.SetSquare(z2); 176 | FieldElem z12; z12.SetSquare(z1); 177 | FieldElem u1; u1.SetMult(x1, z22); 178 | FieldElem u2; u2.SetMult(x2, z12); 179 | FieldElem s1; s1.SetMult(y1, z22); s1.SetMult(s1, z2); 180 | FieldElem s2; s2.SetMult(y2, z12); s2.SetMult(s2, z1); 181 | u1.Normalize(); 182 | u2.Normalize(); 183 | if (u1 == u2) { 184 | s1.Normalize(); 185 | s2.Normalize(); 186 | if (s1 == s2) { 187 | SetDouble(p); 188 | } else { 189 | fInfinity = true; 190 | } 191 | return; 192 | } 193 | FieldElem h; h.SetNeg(u1,1); h += u2; 194 | FieldElem r; r.SetNeg(s1,1); r += s2; 195 | FieldElem r2; r2.SetSquare(r); 196 | FieldElem h2; h2.SetSquare(h); 197 | FieldElem h3; h3.SetMult(h,h2); 198 | z.SetMult(z1,z2); z.SetMult(z, h); 199 | FieldElem t; t.SetMult(u1,h2); 200 | x = t; x *= 2; x += h3; x.SetNeg(x,3); x += r2; 201 | y.SetNeg(x,5); y += t; y.SetMult(y,r); 202 | h3.SetMult(h3,s1); h3.SetNeg(h3,1); 203 | y += h3; 204 | } 205 | 206 | void GroupElemJac::SetAdd(const GroupElemJac &p, const GroupElem &q) { 207 | if (p.fInfinity) { 208 | x = q.x; 209 | y = q.y; 210 | fInfinity = q.fInfinity; 211 | z = FieldElem(1); 212 | return; 213 | } 214 | if (q.fInfinity) { 215 | *this = p; 216 | return; 217 | } 218 | fInfinity = false; 219 | const FieldElem &x1 = p.x, &y1 = p.y, &z1 = p.z, &x2 = q.x, &y2 = q.y; 220 | FieldElem z12; z12.SetSquare(z1); 221 | FieldElem u1 = x1; u1.Normalize(); 222 | FieldElem u2; u2.SetMult(x2, z12); 223 | FieldElem s1 = y1; s1.Normalize(); 224 | FieldElem s2; s2.SetMult(y2, z12); s2.SetMult(s2, z1); 225 | u1.Normalize(); 226 | u2.Normalize(); 227 | if (u1 == u2) { 228 | s1.Normalize(); 229 | s2.Normalize(); 230 | if (s1 == s2) { 231 | SetDouble(p); 232 | } else { 233 | fInfinity = true; 234 | } 235 | return; 236 | } 237 | FieldElem h; h.SetNeg(u1,1); h += u2; 238 | FieldElem r; r.SetNeg(s1,1); r += s2; 239 | FieldElem r2; r2.SetSquare(r); 240 | FieldElem h2; h2.SetSquare(h); 241 | FieldElem h3; h3.SetMult(h,h2); 242 | z = p.z; z.SetMult(z, h); 243 | FieldElem t; t.SetMult(u1,h2); 244 | x = t; x *= 2; x += h3; x.SetNeg(x,3); x += r2; 245 | y.SetNeg(x,5); y += t; y.SetMult(y,r); 246 | h3.SetMult(h3,s1); h3.SetNeg(h3,1); 247 | y += h3; 248 | } 249 | 250 | std::string GroupElemJac::ToString() const { 251 | GroupElemJac cop = *this; 252 | GroupElem aff; 253 | cop.GetAffine(aff); 254 | return aff.ToString(); 255 | } 256 | 257 | void GroupElem::SetJac(GroupElemJac &jac) { 258 | jac.GetAffine(*this); 259 | } 260 | 261 | static const unsigned char order_[] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 262 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE, 263 | 0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B, 264 | 0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x41}; 265 | 266 | static const unsigned char g_x_[] = {0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC, 267 | 0x55,0xA0,0x62,0x95,0xCE,0x87,0x0B,0x07, 268 | 0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9, 269 | 0x59,0xF2,0x81,0x5B,0x16,0xF8,0x17,0x98}; 270 | 271 | static const unsigned char g_y_[] = {0x48,0x3A,0xDA,0x77,0x26,0xA3,0xC4,0x65, 272 | 0x5D,0xA4,0xFB,0xFC,0x0E,0x11,0x08,0xA8, 273 | 0xFD,0x17,0xB4,0x48,0xA6,0x85,0x54,0x19, 274 | 0x9C,0x47,0xD0,0x8F,0xFB,0x10,0xD4,0xB8}; 275 | 276 | // properties of secp256k1's efficiently computable endomorphism 277 | static const unsigned char lambda_[] = {0x53,0x63,0xad,0x4c,0xc0,0x5c,0x30,0xe0, 278 | 0xa5,0x26,0x1c,0x02,0x88,0x12,0x64,0x5a, 279 | 0x12,0x2e,0x22,0xea,0x20,0x81,0x66,0x78, 280 | 0xdf,0x02,0x96,0x7c,0x1b,0x23,0xbd,0x72}; 281 | static const unsigned char beta_[] = {0x7a,0xe9,0x6a,0x2b,0x65,0x7c,0x07,0x10, 282 | 0x6e,0x64,0x47,0x9e,0xac,0x34,0x34,0xe9, 283 | 0x9c,0xf0,0x49,0x75,0x12,0xf5,0x89,0x95, 284 | 0xc1,0x39,0x6c,0x28,0x71,0x95,0x01,0xee}; 285 | static const unsigned char a1b2_[] = {0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd, 286 | 0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15}; 287 | static const unsigned char b1_[] = {0xe4,0x43,0x7e,0xd6,0x01,0x0e,0x88,0x28, 288 | 0x6f,0x54,0x7f,0xa9,0x0a,0xbf,0xe4,0xc3}; 289 | static const unsigned char a2_[] = {0x01, 290 | 0x14,0xca,0x50,0xf7,0xa8,0xe2,0xf3,0xf6, 291 | 0x57,0xc1,0x10,0x8d,0x9d,0x44,0xcf,0xd8}; 292 | 293 | GroupConstants::GroupConstants() : g_x(g_x_), g_y(g_y_), 294 | order(order_, sizeof(order_)), 295 | g(g_x,g_y), 296 | beta(beta_), 297 | lambda(lambda_, sizeof(lambda_)), 298 | a1b2(a1b2_, sizeof(a1b2_)), 299 | b1(b1_, sizeof(b1_)), 300 | a2(a2_, sizeof(a2_)) {} 301 | 302 | const GroupConstants &GetGroupConst() { 303 | static const GroupConstants group_const; 304 | return group_const; 305 | } 306 | 307 | void GroupElemJac::SetMulLambda(const GroupElemJac &p) { 308 | FieldElem beta = GetGroupConst().beta; 309 | *this = p; 310 | x.SetMult(x, beta); 311 | } 312 | 313 | void SplitExp(const Number &exp, Number &exp1, Number &exp2) { 314 | const GroupConstants &c = GetGroupConst(); 315 | Number bnc1, bnc2, bnt1, bnt2, bnn2; 316 | bnn2.SetNumber(c.order); 317 | bnn2.Shift1(); 318 | 319 | bnc1.SetMult(exp, c.a1b2); 320 | bnc1.SetAdd(bnc1, bnn2); 321 | bnc1.SetDiv(bnc1, c.order); 322 | 323 | bnc2.SetMult(exp, c.b1); 324 | bnc2.SetAdd(bnc2, bnn2); 325 | bnc2.SetDiv(bnc2, c.order); 326 | 327 | bnt1.SetMult(bnc1, c.a1b2); 328 | bnt2.SetMult(bnc2, c.a2); 329 | bnt1.SetAdd(bnt1, bnt2); 330 | exp1.SetSub(exp, bnt1); 331 | bnt1.SetMult(bnc1, c.b1); 332 | bnt2.SetMult(bnc2, c.a1b2); 333 | exp2.SetSub(bnt1, bnt2); 334 | } 335 | 336 | } 337 | -------------------------------------------------------------------------------- /group.h: -------------------------------------------------------------------------------- 1 | #ifndef _SECP256K1_GROUP_ 2 | #define _SECP256K1_GROUP_ 3 | 4 | #include 5 | 6 | #include "num.h" 7 | #include "field.h" 8 | 9 | namespace secp256k1 { 10 | 11 | class GroupElemJac; 12 | 13 | /** Defines a point on the secp256k1 curve (y^2 = x^3 + 7) */ 14 | class GroupElem { 15 | protected: 16 | bool fInfinity; 17 | FieldElem x; 18 | FieldElem y; 19 | 20 | public: 21 | 22 | /** Creates the point at infinity */ 23 | GroupElem(); 24 | 25 | /** Creates the point with given affine coordinates */ 26 | GroupElem(const FieldElem &xin, const FieldElem &yin); 27 | 28 | /** Checks whether this is the point at infinity */ 29 | bool IsInfinity() const; 30 | 31 | void SetNeg(const GroupElem &p); 32 | 33 | void GetX(FieldElem &xout); 34 | 35 | void GetY(FieldElem &yout); 36 | 37 | std::string ToString() const; 38 | 39 | void SetJac(GroupElemJac &jac); 40 | 41 | friend class GroupElemJac; 42 | }; 43 | 44 | /** Represents a point on the secp256k1 curve, with jacobian coordinates */ 45 | class GroupElemJac : private GroupElem { 46 | protected: 47 | FieldElem z; 48 | 49 | public: 50 | /** Creates the point at infinity */ 51 | GroupElemJac(); 52 | 53 | /** Creates the point with given affine coordinates */ 54 | GroupElemJac(const FieldElem &xin, const FieldElem &yin); 55 | 56 | GroupElemJac(const GroupElem &in); 57 | 58 | void SetJac(const GroupElemJac &jac); 59 | 60 | void SetAffine(const GroupElem &aff); 61 | 62 | /** Checks whether this is a non-infinite point on the curve */ 63 | bool IsValid() const; 64 | 65 | /** Returns the affine coordinates of this point */ 66 | void GetAffine(GroupElem &aff); 67 | 68 | void GetX(FieldElem &xout); 69 | void GetY(FieldElem &yout); 70 | 71 | bool IsInfinity() const; 72 | 73 | void SetNeg(const GroupElemJac &p); 74 | 75 | /** Sets this point to have a given X coordinate & given Y oddness */ 76 | void SetCompressed(const FieldElem &xin, bool fOdd); 77 | 78 | /** Sets this point to be the EC double of another */ 79 | void SetDouble(const GroupElemJac &p); 80 | 81 | /** Sets this point to be the EC addition of two others */ 82 | void SetAdd(const GroupElemJac &p, const GroupElemJac &q); 83 | 84 | /** Sets this point to be the EC addition of two others (one of which is in affine coordinates) */ 85 | void SetAdd(const GroupElemJac &p, const GroupElem &q); 86 | 87 | std::string ToString() const; 88 | 89 | void SetMulLambda(const GroupElemJac &p); 90 | }; 91 | 92 | class GroupConstants { 93 | private: 94 | const FieldElem g_x; 95 | const FieldElem g_y; 96 | 97 | public: 98 | const Number order; 99 | const GroupElem g; 100 | const FieldElem beta; 101 | const Number lambda, a1b2, b1, a2; 102 | 103 | GroupConstants(); 104 | }; 105 | 106 | const GroupConstants &GetGroupConst(); 107 | 108 | void SplitExp(const Number &exp, Number &exp1, Number &exp2); 109 | 110 | } 111 | 112 | #endif 113 | -------------------------------------------------------------------------------- /num.cpp: -------------------------------------------------------------------------------- 1 | #if defined(USE_NUM_GMP) 2 | #include "num_gmp.cpp" 3 | #elif defined(USE_NUM_OPENSSL) 4 | #include "num_openssl.cpp" 5 | #else 6 | #error "Please select num implementation" 7 | #endif 8 | -------------------------------------------------------------------------------- /num.h: -------------------------------------------------------------------------------- 1 | #ifndef _SECP256K1_NUM_ 2 | #define _SECP256K1_NUM_ 3 | 4 | #if defined(USE_NUM_GMP) 5 | #include "num_gmp.h" 6 | #elif defined(USE_NUM_OPENSSL) 7 | #include "num_openssl.h" 8 | #else 9 | #error "Please select num implementation" 10 | #endif 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /num_builtin.h: -------------------------------------------------------------------------------- 1 | #ifndef _SECP256K1_NUM_GMP_ 2 | #define _SECP256K1_NUM_GMP_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace secp256k1 { 10 | 11 | class Number { 12 | private: 13 | uint64_t n[8]; // 512 bits ought to be enough for everyone 14 | int top; // number of used entries in n 15 | 16 | void FixTop() { 17 | while (top > 0 && n[top-1] == 0) 18 | top--; 19 | } 20 | 21 | int GetNumBytes() { 22 | if (top==0) 23 | return 0; 24 | int ret = 8*(top-1); 25 | uint64_t h = n[top-1]; 26 | while (h>0) { 27 | ret++; 28 | h >>= 8; 29 | } 30 | return ret; 31 | } 32 | 33 | Number(const Number &c) {} 34 | public: 35 | Number() { 36 | top = 0; 37 | } 38 | Number(const unsigned char *bin, int len) { 39 | top = 0; 40 | SetBytes(bin, len); 41 | } 42 | Number &operator=(const Number &x) { 43 | for (int pos = 0; pos < x.top; pos++) 44 | n[pos] = x.n[pos]; 45 | top = x.top; 46 | } 47 | void SetNumber(const Number &x) { 48 | *this = x; 49 | } 50 | void SetBytes(const unsigned char *bin, unsigned int len) { 51 | n[0] = n[1] = n[2] = n[3] = n[4] = n[5] = n[6] = n[7] = 0; 52 | assert(len<=64); 53 | for (int pos = 0; pos < len; pos++) 54 | n[(len-1-pos)/8] |= ((uint64_t)(bin[pos])) << (((len-1-pos)%8)*8); 55 | top = 8; 56 | FixTop(); 57 | } 58 | 59 | void GetBytes(unsigned char *bin, unsigned int len) { 60 | unsigned int size = GetNumBytes(); 61 | assert(size <= len); 62 | memset(bin,0,len); 63 | for (int i=0; i> (((size-1-i)%8)*8)) & 0xFF; 65 | } 66 | 67 | void SetInt(int x) { 68 | n[0] = x; 69 | top = 1; 70 | FixTop(); 71 | } 72 | 73 | void SetModInverse(const Number &x, const Number &m) { 74 | mpz_invert(bn, x.bn, m.bn); 75 | } 76 | 77 | void SetModMul(const Number &a, const Number &b, const Number &m) { 78 | mpz_mul(bn, a.bn, b.bn); 79 | mpz_mod(bn, bn, m.bn); 80 | } 81 | void SetAdd(const Number &a1, const Number &a2) { 82 | 83 | mpz_add(bn, a1.bn, a2.bn); 84 | } 85 | void SetSub(const Number &a1, const Number &a2) { 86 | mpz_sub(bn, a1.bn, a2.bn); 87 | } 88 | void SetMult(const Number &a1, const Number &a2) { 89 | mpz_mul(bn, a1.bn, a2.bn); 90 | } 91 | void SetDiv(const Number &a1, const Number &a2) { 92 | mpz_tdiv_q(bn, a1.bn, a2.bn); 93 | } 94 | void SetMod(const Number &a, const Number &m) { 95 | mpz_mod(bn, a.bn, m.bn); 96 | } 97 | int Compare(const Number &a) const { 98 | return mpz_cmp(bn, a.bn); 99 | } 100 | int GetBits() const { 101 | return mpz_sizeinbase(bn,2); 102 | } 103 | // return the lowest (rightmost) bits bits, and rshift them away 104 | int ShiftLowBits(int bits) { 105 | int ret = mpz_get_ui(bn) & ((1 << bits) - 1); 106 | mpz_fdiv_q_2exp(bn, bn, bits); 107 | return ret; 108 | } 109 | // check whether number is 0, 110 | bool IsZero() const { 111 | return mpz_size(bn) == 0; 112 | } 113 | bool IsOdd() const { 114 | return mpz_get_ui(bn) & 1; 115 | } 116 | bool IsNeg() const { 117 | return mpz_sgn(bn) < 0; 118 | } 119 | void Negate() { 120 | mpz_neg(bn, bn); 121 | } 122 | void Shift1() { 123 | mpz_fdiv_q_2exp(bn, bn, 1); 124 | } 125 | void Inc() { 126 | mpz_add_ui(bn, bn, 1); 127 | } 128 | void SetHex(const std::string &str) { 129 | mpz_set_str(bn, str.c_str(), 16); 130 | } 131 | void SetPseudoRand(const Number &max) { 132 | number_state.gen(bn, max.bn); 133 | } 134 | void SplitInto(int bits, Number &low, Number &high) const { 135 | mpz_t tmp; 136 | mpz_init_set_ui(tmp,1); 137 | mpz_mul_2exp(tmp,tmp,bits); 138 | mpz_sub_ui(tmp,tmp,1); 139 | mpz_and(low.bn, bn, tmp); 140 | mpz_clear(tmp); 141 | mpz_fdiv_q_2exp(high.bn, bn, bits); 142 | } 143 | 144 | std::string ToString() const { 145 | char *str = (char*)malloc(mpz_sizeinbase(bn,16) + 2); 146 | mpz_get_str(str, 16, bn); 147 | std::string ret(str); 148 | free(str); 149 | return ret; 150 | } 151 | }; 152 | 153 | } 154 | 155 | #endif 156 | -------------------------------------------------------------------------------- /num_gmp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "num_gmp.h" 8 | 9 | namespace secp256k1 { 10 | 11 | class NumberState { 12 | private: 13 | gmp_randstate_t rng; 14 | 15 | public: 16 | NumberState() { 17 | gmp_randinit_default(rng); 18 | } 19 | 20 | ~NumberState() { 21 | gmp_randclear(rng); 22 | } 23 | 24 | void gen(mpz_t out, mpz_t size) { 25 | mpz_urandomm(out, rng, size); 26 | } 27 | }; 28 | 29 | static NumberState number_state; 30 | 31 | Number::Number(const Number &x) { 32 | mpz_init_set(bn, x.bn); 33 | } 34 | 35 | Number::Number() { 36 | mpz_init(bn); 37 | } 38 | 39 | Number::~Number() { 40 | mpz_clear(bn); 41 | } 42 | 43 | Number &Number::operator=(const Number &x) { 44 | mpz_set(bn, x.bn); 45 | return *this; 46 | } 47 | 48 | void Number::SetNumber(const Number &x) { 49 | mpz_set(bn, x.bn); 50 | } 51 | 52 | Number::Number(const unsigned char *bin, int len) { 53 | mpz_init(bn); 54 | SetBytes(bin,len); 55 | } 56 | 57 | void Number::SetBytes(const unsigned char *bin, unsigned int len) { 58 | mpz_import(bn, len, 1, 1, 1, 0, bin); 59 | } 60 | 61 | bool Number::CheckBit(int pos) const { 62 | return mpz_tstbit(bn, pos); 63 | } 64 | 65 | void Number::GetBytes(unsigned char *bin, unsigned int len) { 66 | unsigned int size = (mpz_sizeinbase(bn,2)+7)/8; 67 | assert(size <= len); 68 | memset(bin,0,len); 69 | size_t count = 0; 70 | mpz_export(bin + len - size, &count, 1, 1, 1, 0, bn); 71 | assert(count == 0 || size == count); 72 | } 73 | 74 | void Number::SetInt(int x) { 75 | mpz_set_si(bn, x); 76 | } 77 | 78 | void Number::SetModInverse(const Number &x, const Number &m) { 79 | mpz_invert(bn, x.bn, m.bn); 80 | } 81 | 82 | void Number::SetModMul(const Number &a, const Number &b, const Number &m) { 83 | mpz_mul(bn, a.bn, b.bn); 84 | mpz_mod(bn, bn, m.bn); 85 | } 86 | 87 | void Number::SetAdd(const Number &a1, const Number &a2) { 88 | mpz_add(bn, a1.bn, a2.bn); 89 | } 90 | 91 | void Number::SetSub(const Number &a1, const Number &a2) { 92 | mpz_sub(bn, a1.bn, a2.bn); 93 | } 94 | 95 | void Number::SetMult(const Number &a1, const Number &a2) { 96 | mpz_mul(bn, a1.bn, a2.bn); 97 | } 98 | 99 | void Number::SetDiv(const Number &a1, const Number &a2) { 100 | mpz_tdiv_q(bn, a1.bn, a2.bn); 101 | } 102 | 103 | void Number::SetMod(const Number &a, const Number &m) { 104 | mpz_mod(bn, a.bn, m.bn); 105 | } 106 | 107 | int Number::Compare(const Number &a) const { 108 | return mpz_cmp(bn, a.bn); 109 | } 110 | 111 | int Number::GetBits() const { 112 | return mpz_sizeinbase(bn,2); 113 | } 114 | 115 | int Number::ShiftLowBits(int bits) { 116 | int ret = mpz_get_ui(bn) & ((1 << bits) - 1); 117 | mpz_fdiv_q_2exp(bn, bn, bits); 118 | return ret; 119 | } 120 | 121 | bool Number::IsZero() const { 122 | return mpz_size(bn) == 0; 123 | } 124 | 125 | bool Number::IsOdd() const { 126 | return mpz_get_ui(bn) & 1; 127 | } 128 | 129 | bool Number::IsNeg() const { 130 | return mpz_sgn(bn) < 0; 131 | } 132 | 133 | void Number::Negate() { 134 | mpz_neg(bn, bn); 135 | } 136 | 137 | void Number::Shift1() { 138 | mpz_fdiv_q_2exp(bn, bn, 1); 139 | } 140 | 141 | void Number::Inc() { 142 | mpz_add_ui(bn, bn, 1); 143 | } 144 | 145 | void Number::SetHex(const std::string &str) { 146 | mpz_set_str(bn, str.c_str(), 16); 147 | } 148 | 149 | void Number::SetPseudoRand(const Number &max) { 150 | number_state.gen(bn, max.bn); 151 | } 152 | 153 | void Number::SplitInto(int bits, Number &low, Number &high) const { 154 | mpz_t tmp; 155 | mpz_init_set_ui(tmp,1); 156 | mpz_mul_2exp(tmp,tmp,bits); 157 | mpz_sub_ui(tmp,tmp,1); 158 | mpz_and(low.bn, bn, tmp); 159 | mpz_clear(tmp); 160 | mpz_fdiv_q_2exp(high.bn, bn, bits); 161 | } 162 | 163 | std::string Number::ToString() const { 164 | char *str = (char*)malloc(mpz_sizeinbase(bn,16) + 2); 165 | mpz_get_str(str, 16, bn); 166 | std::string ret(str); 167 | free(str); 168 | return ret; 169 | } 170 | 171 | } 172 | -------------------------------------------------------------------------------- /num_gmp.h: -------------------------------------------------------------------------------- 1 | #ifndef _SECP256K1_NUM_GMP_ 2 | #define _SECP256K1_NUM_GMP_ 3 | 4 | #include 5 | #include 6 | 7 | namespace secp256k1 { 8 | 9 | class Number { 10 | private: 11 | mutable mpz_t bn; 12 | Number(const Number &x); 13 | 14 | public: 15 | Number(); 16 | ~Number(); 17 | Number(const unsigned char *bin, int len); 18 | Number &operator=(const Number &x); 19 | void SetNumber(const Number &x); 20 | void SetBytes(const unsigned char *bin, unsigned int len); 21 | void GetBytes(unsigned char *bin, unsigned int len); 22 | void SetInt(int x); 23 | void SetModInverse(const Number &x, const Number &m); 24 | void SetModMul(const Number &a, const Number &b, const Number &m); 25 | void SetAdd(const Number &a1, const Number &a2); 26 | void SetSub(const Number &a1, const Number &a2); 27 | void SetMult(const Number &a1, const Number &a2); 28 | void SetDiv(const Number &a1, const Number &a2); 29 | void SetMod(const Number &a, const Number &m); 30 | int Compare(const Number &a) const; 31 | int GetBits() const; 32 | int ShiftLowBits(int bits); 33 | bool IsZero() const; 34 | bool IsOdd() const; 35 | bool IsNeg() const; 36 | bool CheckBit(int pos) const; 37 | void Negate(); 38 | void Shift1(); 39 | void Inc(); 40 | void SetHex(const std::string &str); 41 | void SetPseudoRand(const Number &max); 42 | void SplitInto(int bits, Number &low, Number &high) const; 43 | std::string ToString() const; 44 | }; 45 | 46 | } 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /num_openssl.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "num_openssl.h" 8 | 9 | namespace secp256k1 { 10 | 11 | class Context { 12 | private: 13 | BN_CTX *ctx; 14 | 15 | operator BN_CTX*() { 16 | return ctx; 17 | } 18 | 19 | friend class Number; 20 | public: 21 | Context() { 22 | ctx = BN_CTX_new(); 23 | } 24 | 25 | ~Context() { 26 | BN_CTX_free(ctx); 27 | } 28 | }; 29 | 30 | Number::operator const BIGNUM*() const { 31 | return &b; 32 | } 33 | 34 | Number::operator BIGNUM*() { 35 | return &b; 36 | } 37 | 38 | Number::Number() { 39 | BN_init(*this); 40 | } 41 | 42 | Number::~Number() { 43 | BN_free(*this); 44 | } 45 | 46 | Number::Number(const unsigned char *bin, int len) { 47 | BN_init(*this); 48 | SetBytes(bin,len); 49 | } 50 | 51 | void Number::SetNumber(const Number &x) { 52 | BN_copy(*this, x); 53 | } 54 | 55 | Number::Number(const Number &x) { 56 | BN_init(*this); 57 | BN_copy(*this, x); 58 | } 59 | 60 | Number &Number::operator=(const Number &x) { 61 | BN_copy(*this, x); 62 | return *this; 63 | } 64 | 65 | void Number::SetBytes(const unsigned char *bin, int len) { 66 | BN_bin2bn(bin, len, *this); 67 | } 68 | 69 | void Number::GetBytes(unsigned char *bin, int len) { 70 | int size = BN_num_bytes(*this); 71 | assert(size <= len); 72 | memset(bin,0,len); 73 | BN_bn2bin(*this, bin + len - size); 74 | } 75 | 76 | void Number::SetInt(int x) { 77 | if (x >= 0) { 78 | BN_set_word(*this, x); 79 | } else { 80 | BN_set_word(*this, -x); 81 | BN_set_negative(*this, 1); 82 | } 83 | } 84 | 85 | void Number::SetModInverse(const Number &x, const Number &m) { 86 | Context ctx; 87 | BN_mod_inverse(*this, x, m, ctx); 88 | } 89 | 90 | void Number::SetModMul(const Number &a, const Number &b, const Number &m) { 91 | Context ctx; 92 | BN_mod_mul(*this, a, b, m, ctx); 93 | } 94 | 95 | void Number::SetAdd(const Number &a1, const Number &a2) { 96 | BN_add(*this, a1, a2); 97 | } 98 | 99 | void Number::SetSub(const Number &a1, const Number &a2) { 100 | BN_sub(*this, a1, a2); 101 | } 102 | 103 | void Number::SetMult(const Number &a1, const Number &a2) { 104 | Context ctx; 105 | BN_mul(*this, a1, a2, ctx); 106 | } 107 | 108 | void Number::SetDiv(const Number &a1, const Number &a2) { 109 | Context ctx; 110 | BN_div(*this, NULL, a1, a2, ctx); 111 | } 112 | 113 | void Number::SetMod(const Number &a, const Number &m) { 114 | Context ctx; 115 | BN_nnmod(*this, a, m, ctx); 116 | } 117 | 118 | int Number::Compare(const Number &a) const { 119 | return BN_cmp(*this, a); 120 | } 121 | 122 | int Number::GetBits() const { 123 | return BN_num_bits(*this); 124 | } 125 | 126 | int Number::ShiftLowBits(int bits) { 127 | BIGNUM *bn = *this; 128 | int ret = BN_is_zero(bn) ? 0 : bn->d[0] & ((1 << bits) - 1); 129 | BN_rshift(*this, *this, bits); 130 | return ret; 131 | } 132 | 133 | bool Number::IsZero() const { 134 | return BN_is_zero((const BIGNUM*)*this); 135 | } 136 | 137 | bool Number::IsOdd() const { 138 | return BN_is_odd((const BIGNUM*)*this); 139 | } 140 | 141 | bool Number::CheckBit(int pos) const { 142 | return BN_is_bit_set((const BIGNUM*)*this, pos); 143 | } 144 | 145 | bool Number::IsNeg() const { 146 | return BN_is_negative((const BIGNUM*)*this); 147 | } 148 | 149 | void Number::Negate() { 150 | BN_set_negative(*this, !IsNeg()); 151 | } 152 | 153 | void Number::Shift1() { 154 | BN_rshift1(*this,*this); 155 | } 156 | 157 | void Number::Inc() { 158 | BN_add_word(*this,1); 159 | } 160 | 161 | void Number::SetHex(const std::string &str) { 162 | BIGNUM *bn = *this; 163 | BN_hex2bn(&bn, str.c_str()); 164 | } 165 | 166 | void Number::SetPseudoRand(const Number &max) { 167 | BN_pseudo_rand_range(*this, max); 168 | } 169 | 170 | void Number::SplitInto(int bits, Number &low, Number &high) const { 171 | BN_copy(low, *this); 172 | BN_mask_bits(low, bits); 173 | BN_rshift(high, *this, bits); 174 | } 175 | 176 | std::string Number::ToString() const { 177 | char *str = BN_bn2hex(*this); 178 | std::string ret(str); 179 | OPENSSL_free(str); 180 | return ret; 181 | } 182 | 183 | } 184 | -------------------------------------------------------------------------------- /num_openssl.h: -------------------------------------------------------------------------------- 1 | #ifndef _SECP256K1_NUM_OPENSSL_ 2 | #define _SECP256K1_NUM_OPENSSL_ 3 | 4 | #include 5 | #include 6 | 7 | namespace secp256k1 { 8 | 9 | class Number { 10 | private: 11 | BIGNUM b; 12 | Number(const Number &x); 13 | 14 | operator const BIGNUM*() const; 15 | operator BIGNUM*(); 16 | public: 17 | Number(); 18 | ~Number(); 19 | Number(const unsigned char *bin, int len); 20 | void SetNumber(const Number &x); 21 | Number &operator=(const Number &x); 22 | void SetBytes(const unsigned char *bin, int len); 23 | void GetBytes(unsigned char *bin, int len); 24 | void SetInt(int x); 25 | void SetModInverse(const Number &x, const Number &m); 26 | void SetModMul(const Number &a, const Number &b, const Number &m); 27 | void SetAdd(const Number &a1, const Number &a2); 28 | void SetSub(const Number &a1, const Number &a2); 29 | void SetMult(const Number &a1, const Number &a2); 30 | void SetDiv(const Number &a1, const Number &a2); 31 | void SetMod(const Number &a, const Number &m); 32 | int Compare(const Number &a) const; 33 | int GetBits() const; 34 | int ShiftLowBits(int bits); 35 | bool IsZero() const; 36 | bool IsOdd() const; 37 | bool IsNeg() const; 38 | bool CheckBit(int pos) const; 39 | void Negate(); 40 | void Shift1(); 41 | void Inc(); 42 | void SetHex(const std::string &str); 43 | void SetPseudoRand(const Number &max); 44 | void SplitInto(int bits, Number &low, Number &high) const; 45 | std::string ToString() const; 46 | }; 47 | 48 | } 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /secp256k1.cpp: -------------------------------------------------------------------------------- 1 | #include "num.cpp" 2 | #include "field.cpp" 3 | #include "group.cpp" 4 | #include "ecmult.cpp" 5 | #include "ecdsa.cpp" 6 | 7 | namespace secp256k1 { 8 | 9 | int VerifyECDSA(const unsigned char *msg, int msglen, const unsigned char *sig, int siglen, const unsigned char *pubkey, int pubkeylen) { 10 | Number m; 11 | Signature s; 12 | GroupElemJac q; 13 | m.SetBytes(msg, msglen); 14 | if (!ParsePubKey(q, pubkey, pubkeylen)) 15 | return -1; 16 | if (!s.Parse(sig, siglen)) { 17 | fprintf(stderr, "Can't parse signature: "); 18 | for (int i=0; i 2 | 3 | #include "num.cpp" 4 | #include "field.cpp" 5 | #include "group.cpp" 6 | #include "ecmult.cpp" 7 | #include "ecdsa.cpp" 8 | 9 | using namespace secp256k1; 10 | 11 | void test_run_ecmult_chain() { 12 | // random starting point A (on the curve) 13 | FieldElem ax; ax.SetHex("8b30bbe9ae2a990696b22f670709dff3727fd8bc04d3362c6c7bf458e2846004"); 14 | FieldElem ay; ay.SetHex("a357ae915c4a65281309edf20504740f0eb3343990216b4f81063cb65f2f7e0f"); 15 | GroupElemJac a(ax,ay); 16 | // two random initial factors xn and gn 17 | Number xn; xn.SetHex("84cc5452f7fde1edb4d38a8ce9b1b84ccef31f146e569be9705d357a42985407"); 18 | Number gn; gn.SetHex("a1e58d22553dcd42b23980625d4c57a96e9323d42b3152e5ca2c3990edc7c9de"); 19 | // two small multipliers to be applied to xn and gn in every iteration: 20 | Number xf; xf.SetHex("1337"); 21 | Number gf; gf.SetHex("7113"); 22 | // accumulators with the resulting coefficients to A and G 23 | Number ae; ae.SetHex("01"); 24 | Number ge; ge.SetHex("00"); 25 | // the point being computed 26 | GroupElemJac x = a; 27 | const Number &order = GetGroupConst().order; 28 | for (int i=0; i<20000; i++) { 29 | // in each iteration, compute X = xn*X + gn*G; 30 | ECMult(x, x, xn, gn); 31 | // also compute ae and ge: the actual accumulated factors for A and G 32 | // if X was (ae*A+ge*G), xn*X + gn*G results in (xn*ae*A + (xn*ge+gn)*G) 33 | ae.SetModMul(ae, xn, order); 34 | ge.SetModMul(ge, xn, order); 35 | ge.SetAdd(ge, gn); 36 | ge.SetMod(ge, order); 37 | // modify xn and gn 38 | xn.SetModMul(xn, xf, order); 39 | gn.SetModMul(gn, gf, order); 40 | } 41 | std::string res = x.ToString(); 42 | assert(res == "(D6E96687F9B10D092A6F35439D86CEBEA4535D0D409F53586440BD74B933E830,B95CBCA2C77DA786539BE8FD53354D2D3B4F566AE658045407ED6015EE1B2A88)"); 43 | // redo the computation, but directly with the resulting ae and ge coefficients: 44 | GroupElemJac x2; ECMult(x2, a, ae, ge); 45 | std::string res2 = x2.ToString(); 46 | assert(res == res2); 47 | } 48 | 49 | void test_point_times_order(const GroupElemJac &point) { 50 | // either the point is not on the curve, or multiplying it by the order results in O 51 | if (!point.IsValid()) 52 | return; 53 | 54 | const GroupConstants &c = GetGroupConst(); 55 | Number zero; zero.SetInt(0); 56 | GroupElemJac res; 57 | ECMult(res, point, c.order, zero); // calc res = order * point + 0 * G; 58 | assert(res.IsInfinity()); 59 | } 60 | 61 | void test_run_point_times_order() { 62 | FieldElem x; x.SetHex("02"); 63 | for (int i=0; i<500; i++) { 64 | GroupElemJac j; j.SetCompressed(x, true); 65 | test_point_times_order(j); 66 | x.SetSquare(x); 67 | } 68 | assert(x.ToString() == "7603CB59B0EF6C63FE6084792A0C378CDB3233A80F8A9A09A877DEAD31B38C45"); // 0x02 ^ (2^500) 69 | } 70 | 71 | void test_wnaf(const Number &number, int w) { 72 | Number x, two, t; 73 | x.SetInt(0); 74 | two.SetInt(2); 75 | WNAF<1023> wnaf(number, w); 76 | int zeroes = -1; 77 | for (int i=wnaf.GetSize()-1; i>=0; i--) { 78 | x.SetMult(x, two); 79 | int v = wnaf.Get(i); 80 | if (v) { 81 | assert(zeroes == -1 || zeroes >= w-1); // check that distance between non-zero elements is at least w-1 82 | zeroes=0; 83 | assert((v & 1) == 1); // check non-zero elements are odd 84 | assert(v <= (1 << (w-1)) - 1); // check range below 85 | assert(v >= -(1 << (w-1)) - 1); // check range above 86 | } else { 87 | assert(zeroes != -1); // check that no unnecessary zero padding exists 88 | zeroes++; 89 | } 90 | t.SetInt(v); 91 | x.SetAdd(x, t); 92 | } 93 | assert(x.Compare(number) == 0); // check that wnaf represents number 94 | } 95 | 96 | void test_run_wnaf() { 97 | Number range, min, n; 98 | range.SetHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); // 2^1024-1 99 | min = range; min.Shift1(); min.Negate(); 100 | for (int i=0; i<100; i++) { 101 | n.SetPseudoRand(range); n.SetAdd(n,min); 102 | test_wnaf(n, 4+(i%10)); 103 | } 104 | } 105 | 106 | void test_ecdsa_sign_verify() { 107 | const GroupConstants &c = GetGroupConst(); 108 | Number msg; msg.SetPseudoRand(c.order); 109 | Number key; key.SetPseudoRand(c.order); 110 | Number nonce; 111 | GroupElemJac pub; ECMultBase(pub, key); 112 | Signature sig; 113 | do { 114 | nonce.SetPseudoRand(c.order); 115 | } while(!sig.Sign(key, msg, nonce)); 116 | assert(sig.Verify(pub, msg)); 117 | msg.Inc(); 118 | assert(!sig.Verify(pub, msg)); 119 | } 120 | 121 | void test_run_ecdsa_sign_verify() { 122 | for (int i=0; i<1000; i++) { 123 | test_ecdsa_sign_verify(); 124 | } 125 | } 126 | 127 | int main(void) { 128 | test_run_wnaf(); 129 | test_run_point_times_order(); 130 | test_run_ecmult_chain(); 131 | test_run_ecdsa_sign_verify(); 132 | return 0; 133 | } 134 | --------------------------------------------------------------------------------