Longfellow ZK 0290cb32
Loading...
Searching...
No Matches
reed_solomon.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_ALGEBRA_REED_SOLOMON_H_
16#define PRIVACY_PROOFS_ZK_LIB_ALGEBRA_REED_SOLOMON_H_
17
18#include <stddef.h>
19
20#include <memory>
21#include <vector>
22
23#include "algebra/utility.h"
24
25namespace proofs {
26
27/*
28The ReedSolomon class interpolates a polynomial given as input in point-eval
29form at a set of different points, thereby computing a form of RS encoding.
30Specifically, the input polynomial of degree d=n-1 is given as evaluations
31at 0, 1, 2, ..., n-1, and the output is the values at n, n+1, n+2, ..., n+m-1.
32The algorithm uses the following relation:
33
34 p(k) = (-1)^d (k-d)(k choose d) sum_{j=0}^{d} (1/k-j)(-1)^j (d choose j)p(j)
35
36which can be efficiently computed using a convolution, whose implementation
37is provided by a ConvolutionFactory for the field.
38
39The const Field& objects that are passed have lifetimes that exceed the call
40durations and can be safely passed by const reference.
41
42*/
43template <class Field, class ConvolutionFactory>
44class ReedSolomon {
45 using Elt = typename Field::Elt;
46 using Convolver = typename ConvolutionFactory::Convolver;
47
48 public:
49 // n is the number of points provided
50 // m is the total number of points output (including the initial n points)
51 ReedSolomon(size_t n, size_t m, const Field& F,
52 const ConvolutionFactory& factory)
53 : f_(F), // could grab this from the factory
54 degree_bound_(n - 1),
55 m_(m),
56 leading_constant_(m - n + 1),
57 binom_i_(n) {
58 // inverses[i]: inverses[i] = 1/i from i = 1 to m-1 (inverses[0] = 0)
59 std::vector<Elt> inverses(m_);
60 AlgebraUtil<Field>::batch_inverse_arithmetic(m, &inverses[0], F);
61 c_ = factory.make(n, m, &inverses[0]);
62 leading_constant_[0] = F.one();
63 binom_i_[0] = F.one();
64 // Set leading_constant_[i] = (i+degree_bound_) choose degree_bound_
65 // (from i=0 to i=m)
66 for (size_t i = 1; i + degree_bound_ < m; ++i) {
67 leading_constant_[i] =
68 F.mulf(leading_constant_[i - 1],
69 F.mulf(F.of_scalar(degree_bound_ + i), inverses[i]));
70 }
71 // Finish computing the leading constants:
72 // (-1)^degree_bound_ (k-degree_bound_) \binom{k}{degree_bound_}
73 for (size_t k = degree_bound_; k < m; ++k) {
74 F.mul(leading_constant_[k - degree_bound_],
75 F.of_scalar(k - degree_bound_));
76 if (degree_bound_ % 2 == 1) {
77 F.neg(leading_constant_[k - degree_bound_]);
78 }
79 }
80
81 for (size_t i = 1; i < n; ++i) {
82 binom_i_[i] =
83 F.mulf(binom_i_[i - 1], F.mulf(F.of_scalar(n - i), inverses[i]));
84 }
85 for (size_t i = 1; i < n; i += 2) {
86 F.neg(binom_i_[i]);
87 }
88 }
89
90 // Given the values of a polynomial of degree at most n at 0, 1, 2, ..., n-1,
91 // this computes the values at n, n+1, n+2, ..., m-1.
92 // (n points go in, m points come out)
93 void interpolate(Elt y[/*m*/]) const {
94 // shorthands
95 const Field& F = f_;
96 size_t n = degree_bound_ + 1; // number of points input
97
98 // Define x[i] = (-1)^i \binom{n}{i} p(i) for i=0 through i=n
99 std::vector<Elt> x(n);
100 for (size_t i = 0; i < n; i++) {
101 x[i] = F.mulf(binom_i_[i], y[i]);
102 }
103
104 std::vector<Elt> T(m_);
105 c_->convolution(&x[0], &T[0]);
106 // Multiply the leading constants by the convolution
107 for (size_t i = n; i < m_; ++i) {
108 y[i] = F.mulf(leading_constant_[i - degree_bound_], T[i]);
109 }
110 }
111
112 private:
113 const Field& f_;
114
115 // n is the number of points input, and degree_bound = n + 1.
116 // degree_bound_ is useful since the LaTeX math is written in terms of it
117 const size_t degree_bound_; // degree bound, i.e., n - 1
118 // total number of points output (points in + new points out)
119 const size_t m_;
120
121 std::unique_ptr<const Convolver> c_;
122
123 // leading_constant_[i] = \binom{i+degree_bound_}{degree_bound_} *
124 // (-1)^{degree_bound_} (i+degree_bound_ - degree_bound_) (from i=0 to i=m-n)
125 // i.e., the leading constant \binom{k}{degree_bound_} *
126 // (-1)^degree_bound_ (k - degree_bound_), shifted left by degree_bound_
127 std::vector<Elt> leading_constant_;
128 // (-1)^i (degree_bound_ choose i) from i=0 to i=degree_bound_
129 std::vector<Elt> binom_i_;
130};
131
132template <class Field, class ConvolutionFactory>
133class ReedSolomonFactory {
134 public:
135 ReedSolomonFactory(const ConvolutionFactory& factory, const Field& f)
136 : factory_(factory), f_(f) {}
137
138 std::unique_ptr<ReedSolomon<Field, ConvolutionFactory>> make(size_t n,
139 size_t m) const {
140 return std::make_unique<ReedSolomon<Field, ConvolutionFactory>>(n, m, f_,
141 factory_);
142 }
143
144 private:
145 const ConvolutionFactory& factory_;
146 const Field& f_;
147};
148} // namespace proofs
149
150#endif // PRIVACY_PROOFS_ZK_LIB_ALGEBRA_REED_SOLOMON_H_
Definition gf2_128.h:63