LLZK 2.0.0
An open-source IR for Zero Knowledge (ZK) circuits
Loading...
Searching...
No Matches
DynamicAPIntHelper.cpp
Go to the documentation of this file.
1//===-- DynamicAPIntHelper.cpp ----------------------------------*- C++ -*-===//
2//
3// Part of the LLZK Project, under the Apache License v2.0.
4// See LICENSE.txt for license information.
5// Copyright 2025 Veridise Inc.
6// SPDX-License-Identifier: Apache-2.0
7//
8//===----------------------------------------------------------------------===//
9
11
12#include "llzk/Util/Compare.h"
13
14#include <llvm/ADT/ArrayRef.h>
15#include <llvm/ADT/SmallString.h>
16#include <llvm/Support/raw_ostream.h>
17
18#include <limits>
19
20using namespace llvm;
21using namespace std;
22
23static DynamicAPInt po2(const DynamicAPInt &e) {
24 // Ensure parameter is not negative and that it can be safely cast to unsigned.
25 assert(e >= 0);
26 assert(e <= std::numeric_limits<unsigned>::max() /* upcast from unsigned -> int64_t */);
27 unsigned shiftAmt = llzk::toAPSInt(e).getZExtValue();
28 APSInt p = APSInt::get(1) << shiftAmt;
29 return llzk::toDynamicAPInt(p);
30}
31
32static DynamicAPInt fromBigEndian(const std::vector<bool> &bits) {
33 APSInt rawInt(bits.size(), /* isUnsigned */ false);
34 for (unsigned i = 0; i < bits.size(); ++i) {
35 rawInt.setBitVal(i, bits[i]);
36 }
37 return llzk::toDynamicAPInt(rawInt);
38}
39
40static DynamicAPInt
41binaryBitOp(const DynamicAPInt &lhs, const DynamicAPInt &rhs, function_ref<bool(bool, bool)> fn) {
42 DynamicAPInt a = lhs, b = rhs;
43 std::vector<bool> bits;
44 while (a != 0 || b != 0) {
45 // bits are sign extended
46 bool abit = a != 0 ? bool(int64_t(a % 2)) : lhs < 0;
47 bool bbit = b != 0 ? bool(int64_t(b % 2)) : rhs < 0;
48 bits.push_back(fn(abit, bbit));
49 a /= 2;
50 b /= 2;
51 }
52 // Insert final sign bit, as the above will ignore 0 sign bits. This is also
53 // acceptable when both numbers are signed, as it acts as a sign extension.
54 bits.push_back(fn(lhs < 0, rhs < 0));
55 return fromBigEndian(bits);
56}
57
58namespace llzk {
59
60DynamicAPInt operator&(const DynamicAPInt &lhs, const DynamicAPInt &rhs) {
61 auto fn = [](bool a, bool b) { return a && b; };
62 return binaryBitOp(lhs, rhs, fn);
63}
64
65DynamicAPInt operator|(const DynamicAPInt &lhs, const DynamicAPInt &rhs) {
66 auto fn = [](bool a, bool b) { return a || b; };
67 return binaryBitOp(lhs, rhs, fn);
68}
69
70DynamicAPInt operator^(const DynamicAPInt &lhs, const DynamicAPInt &rhs) {
71 auto fn = [](bool a, bool b) { return a ^ b; };
72 return binaryBitOp(lhs, rhs, fn);
73}
74
75DynamicAPInt operator<<(const DynamicAPInt &lhs, const DynamicAPInt &rhs) { return lhs * po2(rhs); }
76
77DynamicAPInt operator>>(const DynamicAPInt &lhs, const DynamicAPInt &rhs) {
78 if (lhs >= 0) {
79 return lhs / po2(rhs);
80 } else {
81 // round towards negative infinity
82 DynamicAPInt divisor = po2(rhs);
83 if (lhs % divisor == 0) {
84 return lhs / divisor;
85 } else {
86 return (lhs - (divisor - 1)) / divisor;
87 }
88 }
89}
90
91DynamicAPInt toDynamicAPInt(StringRef str) {
92 APSInt parsedInt(str);
93 return toDynamicAPInt(parsedInt);
94}
95
96DynamicAPInt toDynamicAPInt(const APSInt &i) {
97 if (i.getBitWidth() <= 64) {
98 // Fast path for smaller values, just use the int64_t conversion
99 return DynamicAPInt(i.isNegative() ? i.getSExtValue() : static_cast<int64_t>(i.getZExtValue()));
100 }
101
102 DynamicAPInt res(0), po2(1);
103 // Since LLVM 20 doesn't have a direct APInt to DynamicAPInt constructor, we
104 // manually construct the DynamicAPInt from bits of the input.
105 // We use the positive representation so our negation works at the end.
106 APSInt raw = i < 0 ? -i : i;
107 for (unsigned b = 0; b < raw.getActiveBits(); b++) {
108 DynamicAPInt bitSet(raw[b]);
109 res += (bitSet * po2);
110 po2 *= 2;
111 }
112 if (i.isNegative() && res > 0) {
113 res = -res;
114 }
115 return res;
116}
117
118APSInt toAPSInt(const DynamicAPInt &i) {
119 if (numeric_limits<int64_t>::min() <= i && i <= numeric_limits<int64_t>::max()) {
120 // Fast path for smaller values, just use the int64_t conversion
121 return APSInt::get(int64_t(i));
122 }
123
124 // Else, convert to string and parse back as an APSInt.
125 // This may not be the most efficient implementation, but it is the cleanest
126 // due to the lack of direct conversions between DynamicAPInt and APInts.
127 SmallString<64> repr;
128 raw_svector_ostream(repr) << i;
129
130 APSInt res(repr);
131 // For consistency, we add a bit and mark these as signed integers, since
132 // DynamicAPInts are inherently signed.
133 res = res.extend(res.getBitWidth() + 1);
134 res.setIsSigned(true);
135
136 return res;
137}
138
139APInt toAPInt(const DynamicAPInt &val, unsigned bitWidth) {
140 SmallString<64> str;
141 raw_svector_ostream(str) << val;
142 return APInt(bitWidth + 1, str, 10);
143}
144
145DynamicAPInt modExp(const DynamicAPInt &base, const DynamicAPInt &exp, const DynamicAPInt &mod) {
146 DynamicAPInt result(1);
147 DynamicAPInt b = base;
148 DynamicAPInt e = exp;
149 DynamicAPInt one(1);
150
151 while (e != 0) {
152 if (e % 2 != 0) {
153 result = (result * b) % mod;
154 }
155
156 b = (b * b) % mod;
157 e = e >> one;
158 }
159 return result;
160}
161
162DynamicAPInt modInversePrime(const DynamicAPInt &f, const DynamicAPInt &p) {
163 assert(f != 0 && "0 has no inverse");
164 // Fermat: f^(p-2) mod p
165 DynamicAPInt exp = p - 2;
166 DynamicAPInt result = modExp(f, exp, p);
167 assert((f * result) % p == 1 && "inverse is incorrect");
168 return result;
169}
170
171} // namespace llzk
This file implements helper methods for constructing DynamicAPInts.
ExpressionValue mod(const llvm::SMTSolverRef &solver, const ExpressionValue &lhs, const ExpressionValue &rhs)
Interval operator|(const Interval &lhs, const Interval &rhs)
Interval operator^(const Interval &lhs, const Interval &rhs)
DynamicAPInt toDynamicAPInt(StringRef str)
Interval operator<<(const Interval &lhs, const Interval &rhs)
APInt toAPInt(const DynamicAPInt &val, unsigned bitWidth)
Interval operator>>(const Interval &lhs, const Interval &rhs)
Interval operator&(const Interval &lhs, const Interval &rhs)
DynamicAPInt modInversePrime(const DynamicAPInt &f, const DynamicAPInt &p)
APSInt toAPSInt(const DynamicAPInt &i)
DynamicAPInt modExp(const DynamicAPInt &base, const DynamicAPInt &exp, const DynamicAPInt &mod)