barretenberg
Loading...
Searching...
No Matches
secp256k1_endo_notes.hpp
1#pragma once
2
3#include "barretenberg/numeric/uintx/uintx.hpp"
4#include "secp256k1.hpp"
5
6namespace secp256k1_params {
8 uint64_t endo_g1_lo = 0;
9 uint64_t endo_g1_mid = 0;
10 uint64_t endo_g1_hi = 0;
11 uint64_t endo_g1_hihi = 0;
12 uint64_t endo_g2_lo = 0;
13 uint64_t endo_g2_mid = 0;
14 uint64_t endo_g2_hi = 0;
15 uint64_t endo_g2_hihi = 0;
16 uint64_t endo_minus_b1_lo = 0;
17 uint64_t endo_minus_b1_mid = 0;
18 uint64_t endo_b2_lo = 0;
19 uint64_t endo_b2_mid = 0;
20 uint64_t endo_a1_lo = 0;
21 uint64_t endo_a1_mid = 0;
22 uint64_t endo_a1_hi = 0;
23 uint64_t endo_a2_lo = 0;
24 uint64_t endo_a2_mid = 0;
25 uint64_t endo_a2_hi = 0;
26
27 bool real = false;
28};
29[[maybe_unused]] static basis_vectors get_endomorphism_basis_vectors(const secp256k1::fr& lambda)
30{
31 uint512_t approximate_square_root;
32 uint512_t z = (uint512_t(secp256k1::fr::modulus) + uint512_t(2)) >> 1;
33 auto y = uint512_t(secp256k1::fr::modulus);
34 while (z < y) {
35 y = z;
36 z = (uint512_t(secp256k1::fr::modulus) / z + z) >> 1;
37 }
38 approximate_square_root = y;
39 // Run the extended greatest common divisor algorithm until out * (\lambda + 1) < approximate_square_root
40
41 uint512_t u(lambda);
42 uint512_t v(secp256k1::fr::modulus);
43 uint512_t x1 = 1;
44 uint512_t y1 = 0;
45 uint512_t x2 = 0;
46 uint512_t y2 = 1;
47
48 uint512_t a0 = 0;
49 uint512_t b0 = 0;
50
51 uint512_t a1 = 0;
52 uint512_t b1 = 0;
53
54 uint512_t a2 = 0;
55 uint512_t b2 = 0;
56
57 uint512_t prevOut = 0;
58 uint512_t i = 0;
59 uint512_t out = 0;
60 uint512_t x = 0;
61
62 while (u != 0) {
63 uint512_t q = v / u;
64 out = v - uint512_t(uint512_t(q) * uint512_t(u));
65 x = x2 - (q * x1);
66 uint512_t y = y2 - (q * y1);
67 if ((a1 == 0) && (out < approximate_square_root)) {
68 a0 = -prevOut;
69 b0 = x1;
70 a1 = -out;
71 b1 = x;
72 } else if ((a1 > 0) && (++i == 2)) {
73 break;
74 }
75 prevOut = out;
76
77 v = u;
78 u = out;
79 x2 = x1;
80 x1 = x;
81 y2 = y1;
82 y1 = y;
83 }
84
85 a2 = -out;
86 b2 = x;
87
88 uint512_t len1 = (a1 * a1) + (b1 * b1);
89 uint512_t len2 = (a2 * a2) + (b2 * b2);
90 if (len2 >= len1) {
91 a2 = a0;
92 b2 = b0;
93 }
94
95 if (a1.get_msb() >= 128) {
96 a1 = -a1;
97 b1 = -b1;
98 }
99 if (a2.get_msb() >= 128) {
100 a2 = -a2;
101 b2 = -b2;
102 }
103
104 uint512_t minus_b1 = -b1;
105 uint512_t shift256 = uint512_t(1) << 384;
106 uint512_t g1 = (-b1 * shift256) / uint512_t(secp256k1::fr::modulus);
107 uint512_t g2 = (b2 * shift256) / uint512_t(secp256k1::fr::modulus);
108
109 basis_vectors result;
110 result.endo_g1_lo = g1.lo.data[0];
111 result.endo_g1_mid = g1.lo.data[1];
112 result.endo_g1_hi = g1.lo.data[2];
113 result.endo_g1_hihi = g1.lo.data[3];
114 result.endo_g2_lo = g2.lo.data[0];
115 result.endo_g2_mid = g2.lo.data[1];
116 result.endo_g2_hi = g2.lo.data[2];
117 result.endo_g2_hihi = g2.lo.data[3];
118 result.endo_minus_b1_lo = minus_b1.lo.data[0];
119 result.endo_minus_b1_mid = minus_b1.lo.data[1];
120 result.endo_b2_lo = b2.lo.data[0];
121 result.endo_b2_mid = b2.lo.data[1];
122 result.endo_a1_lo = a1.lo.data[0];
123 result.endo_a1_mid = a1.lo.data[1];
124 result.endo_a1_hi = a1.lo.data[2];
125 result.endo_a2_lo = a2.lo.data[0];
126 result.endo_a2_mid = a2.lo.data[1];
127 result.endo_a2_hi = a2.lo.data[2];
128 return result;
129}
130
131[[maybe_unused]] static std::pair<secp256k1::fq, secp256k1::fr> get_endomorphism_scalars()
132{
133 // find beta \in secp256k1::fq and lambda \in secp256k1::fr such that:
134
135 // 1. beta^3 = 1 mod q
136 // 2. lambda^3 = 1 mod r
137 // 3. for [P] \in G with coordinates (P.x, P.y) \in secp256k1::fq:
138 // \lambda.[P] = (\beta . P.x, P.y)
139 const secp256k1::fq beta = secp256k1::fq::cube_root_of_unity();
140 const secp256k1::fr lambda = secp256k1::fr::cube_root_of_unity();
141
142 if (beta * beta * beta != secp256k1::fq(1)) {
143 std::cerr << "beta is not a cube root of unity" << std::endl;
144 }
145 if (lambda * lambda * lambda != secp256k1::fr(1)) {
146 std::cerr << "lambda is not a cube root of unity" << std::endl;
147 }
148
149 secp256k1::g1::element P = secp256k1::g1::one;
150 secp256k1::g1::element endoP = P;
151 endoP.x *= beta;
152
153 if (P * lambda == endoP) {
154 return { beta, lambda };
155 }
156 endoP.x *= beta;
157 if ((P * lambda) == endoP) {
158 return { beta * beta, lambda };
159 }
160 endoP.y = -endoP.y;
161 std::cerr << "could not find endomorphism scalars???" << std::endl;
162 return { secp256k1::fq(0), secp256k1::fr(0) };
163}
164}; // namespace secp256k1_params
element class. Implements ecc group arithmetic using Jacobian coordinates See https://hyperelliptic....
Definition: element.hpp:27
Definition: field_declarations.hpp:24
Definition: secp256k1_endo_notes.hpp:7