Longfellow ZK 0290cb32

Loading...
Searching...
No Matches
ceildiv.h
1// Copyright 2025 Google LLC.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#ifndef PRIVACY_PROOFS_ZK_LIB_UTIL_CEILDIV_H_
16#define PRIVACY_PROOFS_ZK_LIB_UTIL_CEILDIV_H_
17
18// This package holds basic math utility functions.
19
20#include <cstddef>
21#include <cstdint>
22
23 namespace proofs {
24
25// ceil(a/b)
26 template <class T>
27T ceildiv(T a, T b) {
28 return (a + (b - 1)) / b;
29}
30
31 inline size_t lg(size_t n) {
32 size_t lgk = 0, k = 1;
33 while (k < n) {
34 k *= 2;
35 lgk += 1;
36 }
37 return lgk;
38}
39
40// Morton-order operations
41 namespace morton {
42// extract even bits (pack)
43 inline uint64_t even(uint64_t x) {
44 x &= 0x5555555555555555ull;
45 x |= (x >> 1);
46 x &= 0x3333333333333333ull;
47 x |= (x >> 2);
48 x &= 0x0F0F0F0F0F0F0F0Full;
49 x |= (x >> 4);
50 x &= 0x00FF00FF00FF00FFull;
51 x |= (x >> 8);
52 x &= 0x0000FFFF0000FFFFull;
53 x |= (x >> 16);
54 x &= 0x00000000FFFFFFFFull;
55 return x;
56}
57
58// inverse of even (unpack)
59 inline uint64_t uneven(uint64_t x) {
60 x &= 0x00000000FFFFFFFFull;
61 x |= (x << 16);
62 x &= 0x0000FFFF0000FFFFull;
63 x |= (x << 8);
64 x &= 0x00FF00FF00FF00FFull;
65 x |= (x << 4);
66 x &= 0x0F0F0F0F0F0F0F0Full;
67 x |= (x << 2);
68 x &= 0x3333333333333333ull;
69 x |= (x << 1);
70 x &= 0x5555555555555555ull;
71 return x;
72}
73
74// Given two integers X and Y represented
75// as (even, odd) bits (X0, X1) and
76// (Y0, Y1), set (X0, X1) to the even/odd
77// representation of X+Y
78 template <class T>
79 static void add(T *x0, T *x1, T y0, T y1) {
80 // Given two arrays X[i] and Y[i] of bits, the goal
81 // is to build an adder. One way to build an adder
82 // is to switch to the generate/propagate representation
83 // G[i] = X[i] & Y[i]
84 // P[i] = X[i] ^ Y[i]
85 // where G[i] means "position i generates a carry" and P[i] means
86 // "position i propagates the carry coming from position i-1".
87 //
88 // Generate/propagate can be extended to pairs of positions
89 // via the equations
90 //
91 // G = G[i+1] ^ (G[i] ^ P[i+1])
92 // P = P[i+1] & P[i]. (1)
93 //
94 // (This is all well-known adder stuff that has been known since
95 // at least the '50s).
96 //
97 // Our strategy is thus: convert the addends into G/P representation;
98 // combine the [2i] and [2i+1] positions via Equation (1), and
99 // use the C "+" operation to propagate the carry over one array.
100 //
101 // The fun part is, how do you use the C adder to propagate G.
102 // The standard form of the adder is:
103 //
104 // (G, P) = (X & Y, X ^ Y)
105 // G' = propagate G in any convenient way
106 // (X + Y) = RESULT = P ^ G'
107 //
108 // and thus we can extract the propagated G' as G' = (X + Y) ^ X ^ Y.
109 //
110 // The other fun part is, given G and P, how do you go back to X and
111 // Y that can be fed to the C adder? The transformation (X, Y) -> (G, P)
112 // is not injective, but any inverse will work. We choose
113 //
114 // X = G
115 // Y = P ^ G
116
117 // Convert inputs into (G, P) form.
118 T g0 = *x0 & y0, g1 = *x1 & y1;
119 T p0 = *x0 ^ y0, p1 = *x1 ^ y1;
120
121 // Combine the two (G, P) inputs.
122 T g = g1 ^ (g0 & p1);
123 T p = p0 & p1;
124
125 // Convert back into (X, Y) = (G, P ^ G) and compute
126 // GPRIME = (X + Y) ^ X ^ Y, which simplifies to (X + Y) ^ P
127 // because X = G and Y = P ^ G.
128 // Here we lose the carry of the addition, making it impossible
129 // to output a global carry.
130 T gprime = (g + (p ^ g)) ^ p;
131
132 // XOR the propagated carries back into P
133 *x0 = gprime ^ p0;
134 *x1 = g0 ^ (gprime & p0) ^ p1;
135}
136
137// a-b via ~(~a + b)
138 template <class T>
139 static void sub(T *x0, T *x1, T y0, T y1) {
140 *x0 = ~*x0;
141 *x1 = ~*x1;
142 add(x0, x1, y0, y1);
143 *x0 = ~*x0;
144 *x1 = ~*x1;
145}
146
147// a < b via (a - b) < 0. Since we don't have
148// the output carry of the subtraction, we pretend that
149// the result is signed.
150 template <class T>
151 static bool lt(T x0, T x1, T y0, T y1) {
152 sub(&x0, &x1, y0, y1);
153 return (x1 >> (8 * sizeof(T) - 1)) == 1;
154}
155
156 template <class T>
157 static bool eq(T x0, T x1, T y0, T y1) {
158 return x0 == y0 && x1 == y1;
159}
160
161} // namespace morton
162} // namespace proofs
163
164#endif // PRIVACY_PROOFS_ZK_LIB_UTIL_CEILDIV_H_