kzg 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4ef0ee512428138b4158c95a1ff67254af2926668a45e812df640725108a2d9b
4
- data.tar.gz: e1673fafdefa436f0c10aa7639ba68431831777718a38ecd5374101847a41fea
3
+ metadata.gz: 1d030fcbbf815eafe9c538839946e6337c2e9c60f1bcce5de79172b453c96fe9
4
+ data.tar.gz: 68c3d99c0cb6fea2f16e3617df6d198cae2cb352f22cd66c982ba362731a778c
5
5
  SHA512:
6
- metadata.gz: 7a78076f208b2397f6c2dddd271dbe3ed47ba0ae1794b06451647639b70989f10bc5f52d6cd3ef80fe9fd1fe49535bfa3fb4b168402c4a2c87be9ade0cebfb6b
7
- data.tar.gz: dc12b60adf07dd975c05cf44c0b3c01002714d7d11e9f2cee340b1b89097b253386ae9109f4859d1eba28e267928f90f7afe9ea17449ccf8cfa25da293d4b281
6
+ metadata.gz: a3cae69f35050d6dba026231c2d783204359140a94e406676fb178ff58cc1bdbe1a1e2e73124ea29679a4d5c3b95c22b0c5b90d1d7a2ea4c394bf9317b4926a4
7
+ data.tar.gz: 1d21a4db43881ce872e41954b116cee5603ee80a8b8e3b7e7b7efc01c317d9addb5c9cc78b07a84898279be41d0b941166ee6840e90be95e92929298e89f32ec
data/.rubocop.yml CHANGED
@@ -10,7 +10,7 @@ RSpec/ExampleLength:
10
10
  Metrics:
11
11
  Enabled: false
12
12
  RSpec/MultipleExpectations:
13
- Max: 5
13
+ Enabled: false
14
14
  Style/IfUnlessModifier:
15
15
  Enabled: false
16
16
  Style/WhileUntilModifier:
data/Gemfile CHANGED
@@ -12,4 +12,6 @@ gem 'rspec', '~> 3.0'
12
12
  gem 'prettier'
13
13
 
14
14
  gem 'rubocop-rake'
15
- gem 'rubocop-rspec'
15
+ gem 'rubocop-rspec'
16
+
17
+ gem 'parallel_tests'
data/README.md CHANGED
@@ -61,7 +61,19 @@ The committer can compute proof that the value of the polynomial (f(x)) for any
61
61
  proof = commitment.compute_proof(35)
62
62
  ```
63
63
 
64
- This proof is point in the `BLS::PointG1`.
64
+ This proof is a point in the `BLS::PointG1`.
65
+
66
+ #### Multi proof
67
+
68
+ A multi-proof for disclosing multiple x values is created as follows:
69
+
70
+ ```ruby
71
+ x = [1, 2, 3]
72
+
73
+ multi_proof = commitment.compute_multi_proof(x)
74
+ ```
75
+
76
+ This proof is a point in the `BLS::PointG1`.
65
77
 
66
78
  ### Verify
67
79
 
@@ -73,6 +85,16 @@ y = 808951170278371
73
85
  setting.valid_proof?(commitment.value, proof, x, y)
74
86
  ```
75
87
 
88
+ #### Multi proof
89
+
90
+ The validity of multiple proofs disclosing more than one value can be verified as follows:
91
+
92
+ ```ruby
93
+ x = [1, 2, 3]
94
+ y = [55, 9217, 280483]
95
+ setting.valid_multi_proof?(commitment.value, multi_proof, x, y)
96
+ ```
97
+
76
98
  ### Use as vector commitment
77
99
 
78
100
  When used as a Vector commitment, the value to be committed is encoded in a polynomial expression as the evaluated value of the polynomial.
data/kzg.gemspec CHANGED
@@ -29,7 +29,7 @@ Gem::Specification.new do |spec|
29
29
 
30
30
  # Uncomment to register a new dependency of your gem
31
31
  # spec.add_dependency "example-gem", "~> 1.0"
32
- spec.add_dependency 'bls12-381', '>= 0.2.1'
32
+ spec.add_dependency 'bls12-381', '>= 0.2.2'
33
33
 
34
34
  # For more information and examples about making a new gem, checkout our
35
35
  # guide at: https://bundler.io/guides/creating_gem.html
@@ -7,11 +7,19 @@ module KZG
7
7
 
8
8
  # Create commitment
9
9
  # @param [KZG::Setting] setting
10
- # @param [Array(Integer | BLS::Fr)] coeffs Coefficients of polynomial equation.
11
- def initialize(setting, polynomial, value)
10
+ # @param [KZG::Polynomial] polynomial
11
+ def initialize(setting, polynomial)
12
12
  @setting = setting
13
13
  @polynomial = polynomial
14
- @value = value
14
+ @value =
15
+ polynomial
16
+ .coeffs
17
+ .map
18
+ .with_index do |c, i|
19
+ c = c.is_a?(BLS::Fr) ? c : BLS::Fr.new(c)
20
+ c.value.zero? ? BLS::PointG1::ZERO : setting.g1_points[i] * c
21
+ end
22
+ .inject(&:+)
15
23
  end
16
24
 
17
25
  # Create commitment using coefficients.
@@ -22,25 +30,30 @@ module KZG
22
30
  raise KZG::Error,
23
31
  "coeffs length is greater than the number of secret parameters."
24
32
  end
25
- value =
26
- coeffs
27
- .map
28
- .with_index do |c, i|
29
- setting.g1_points[i] * (c.is_a?(BLS::Fr) ? c : BLS::Fr.new(c))
30
- end
31
- .inject(&:+)
32
- Commitment.new(setting, KZG::Polynomial.new(coeffs), value)
33
+ Commitment.new(setting, KZG::Polynomial.new(coeffs))
33
34
  end
34
35
 
35
36
  # Compute KZG proof for polynomial in coefficient form at position x.
36
37
  # @param [Integer] x Position
37
38
  # @return [BLS::PointG1] Proof.
38
39
  def compute_proof(x)
39
- divisor = Array.new(2)
40
- divisor[0] = BLS::Fr.new(x).negate
41
- divisor[1] = BLS::Fr::ONE
42
- quotient_poly = polynomial.poly_long_div(divisor)
43
- Commitment.from_coeffs(setting, quotient_poly).value
40
+ divisor = Polynomial.new([BLS::Fr.new(x).negate, BLS::Fr::ONE])
41
+ quotient_poly = polynomial / divisor
42
+ Commitment.new(setting, quotient_poly).value
43
+ end
44
+
45
+ # Compute KZG multi proof using list of x coordinate.
46
+ # @param [Array(Integer)] x An array of x coordinate.
47
+ # @return [BLS::PointG1]
48
+ def compute_multi_proof(x)
49
+ y = x.map { |i| polynomial.eval_at(i) }
50
+ # compute i(x)
51
+ i_poly = Polynomial.lagrange_interpolate(x, y)
52
+ # compute z(x)
53
+ z_poly = Polynomial.zero_poly(x)
54
+ # compute q(x) = (p(x) - i(x)) / z(x)
55
+ quotient_poly = (polynomial - i_poly) / z_poly
56
+ Commitment.new(setting, quotient_poly).value
44
57
  end
45
58
  end
46
59
  end
@@ -37,34 +37,95 @@ module KZG
37
37
  Polynomial.new(coeffs)
38
38
  end
39
39
 
40
- # Evaluates a polynomial expression with the specified value +x+.
41
- # @param [Integer|BLS::Fr] x
42
- # @return [BLS::Fr]
40
+ # Create polynomial from array of x coordinate like f(x) = (x - x0)(x - x1)...(x - xn)
41
+ # @param [Array(Integer)] x An array of x coordinate.
42
+ # @return [KZG::Polynomial]
43
+ def self.zero_poly(x)
44
+ poleis =
45
+ x.map { |v| Polynomial.new([BLS::Fr.new(v).negate, BLS::Fr::ONE]) }
46
+ poleis[1..].inject(poleis.first) { |result, poly| result * poly }
47
+ end
48
+
49
+ # Evaluate polynomial for given +x+ using Horner's method.
50
+ # @param [Integer | BLS::Fr] x
51
+ # @return [BLS::Fr] Evaluated value.
43
52
  def eval_at(x)
44
- power = x.is_a?(BLS::Fr) ? x : BLS::Fr.new(x)
45
- sum = coeffs.first
46
- coeffs[1..].each do |c|
47
- sum += c * power
48
- power *= power
53
+ x = x.is_a?(BLS::Fr) ? x : BLS::Fr.new(x)
54
+ return BLS::Fr::ZERO if coeffs.empty?
55
+ return coeffs.first if x.value.zero?
56
+ last = coeffs[coeffs.length - 1]
57
+ (coeffs.length - 2).step(0, -1) do |i|
58
+ tmp = last * x
59
+ last = tmp + coeffs[i]
60
+ end
61
+ last
62
+ end
63
+
64
+ # Returns a new polynomial that is the sum of the given polynomial and this polynomial.
65
+ # @param [KZG::Polynomial] other
66
+ # @return [KZG::Polynomial] Sum of polynomial.
67
+ # @raise ArgumentError
68
+ def add(other)
69
+ unless other.is_a?(Polynomial)
70
+ raise ArgumentError, "add target must be Polynomial"
49
71
  end
50
- sum
72
+
73
+ sum = process(coeffs, other.coeffs) { |a, b| a + b }
74
+ Polynomial.new(sum)
75
+ end
76
+ alias + add
77
+
78
+ # Returns a new polynomial subtracting the given polynomial from self.
79
+ # @param [KZG::Polynomial] other
80
+ # @return [KZG::Polynomial] Subtracted polynomial.
81
+ # @raise ArgumentError
82
+ def sub(other)
83
+ unless other.is_a?(Polynomial)
84
+ raise ArgumentError, "subtract target must be Polynomial"
85
+ end
86
+
87
+ Polynomial.new(process(coeffs, other.coeffs) { |a, b| a - b })
51
88
  end
89
+ alias - sub
52
90
 
53
- # Long polynomial division for two polynomials in coefficient form
54
- # @param [Array(BLS::Fr)] divisor Array of divisor.
55
- # @return [Array(BLS::Fr)]
56
- def poly_long_div(divisor)
57
- a = coeffs
91
+ # Return a new polynomial that multiply self and the given polynomial.
92
+ # @param [KZG::Polynomial] other Other polynomial
93
+ # @return [KZG::Polynomial] Multiplied polynomial
94
+ # @return ArgumentError
95
+ def multiply(other)
96
+ unless other.is_a?(Polynomial)
97
+ raise ArgumentError, "multiply target must be Polynomial"
98
+ end
99
+ new_coeffs = Array.new(coeffs.length + other.coeffs.length - 1)
100
+ coeffs.each.with_index do |a, i|
101
+ other.coeffs.each.with_index do |b, j|
102
+ k = i + j
103
+ new_coeffs[k] = a * b + (new_coeffs[k] || BLS::Fr::ZERO)
104
+ end
105
+ end
106
+ Polynomial.new(new_coeffs)
107
+ end
108
+ alias * multiply
109
+
110
+ # Return a new polynomial that divide self and the given polynomial, i.e. self / other.
111
+ # @param [KZG::Polynomial] other Other polynomial
112
+ # @return [KZG::Polynomial] Divided polynomial
113
+ # @return ArgumentError
114
+ def div(other)
115
+ unless other.is_a?(Polynomial)
116
+ raise ArgumentError, "divide target must be Polynomial"
117
+ end
118
+ a = coeffs.dup
58
119
  a_pos = a.length - 1
59
- b_pos = divisor.length - 1
120
+ b_pos = other.coeffs.length - 1
60
121
  diff = a_pos - b_pos
61
122
  quotient_poly = []
62
123
 
63
124
  while diff >= 0
64
- quot = a[a_pos] / divisor[b_pos]
125
+ quot = a[a_pos] / other.coeffs[b_pos]
65
126
  i = b_pos
66
127
  while i >= 0
67
- tmp = quot * divisor[i]
128
+ tmp = quot * other.coeffs[i]
68
129
  tmp2 = a[diff + i] - tmp
69
130
  a[diff + i] = tmp2
70
131
  i -= 1
@@ -73,7 +134,24 @@ module KZG
73
134
  a_pos -= 1
74
135
  diff -= 1
75
136
  end
76
- quotient_poly
137
+ Polynomial.new(quotient_poly)
138
+ end
139
+ alias / div
140
+
141
+ def ==(other)
142
+ return false unless other.is_a?(Polynomial)
143
+ coeffs == other.coeffs
144
+ end
145
+
146
+ private
147
+
148
+ def process(a, b)
149
+ length = [a.length, b.length].max
150
+ length.times.map do |i|
151
+ c1 = i < a.length ? a[i] : BLS::Fr::ZERO
152
+ c2 = i < b.length ? b[i] : BLS::Fr::ZERO
153
+ yield(c1, c2)
154
+ end
77
155
  end
78
156
  end
79
157
  end
data/lib/kzg/setting.rb CHANGED
@@ -5,12 +5,10 @@ module KZG
5
5
  class Setting
6
6
  attr_reader :g1_points, :g2_points
7
7
 
8
- # @param [Array[BLS::PointG1]] g1s
9
- # @param [Array[BLS::PointG2]] g2s
8
+ # @param [Array(BLS::PointG1)] g1_points
9
+ # @param [Array(BLS::PointG2)] g2_points
10
10
  def initialize(g1_points, g2_points)
11
- if !g1_points.is_a?(Array) || !g2_points.is_a?(Array)
12
- raise KZG::Error, "g1_points and g2_points must be array."
13
- end
11
+ raise KZG::Error, "g1_points must be array." unless g1_points.is_a?(Array)
14
12
  unless g1_points.all? { |g| g.is_a?(BLS::PointG1) }
15
13
  raise KZG::Error, "All elements of g1_points must be BLS::PointG1."
16
14
  end
@@ -34,8 +32,8 @@ module KZG
34
32
  def valid_proof?(commit_point, proof, x, y)
35
33
  x = x.is_a?(BLS::Fr) ? x : BLS::Fr.new(x)
36
34
  y = y.is_a?(BLS::Fr) ? y : BLS::Fr.new(y)
37
- xg2 = BLS::PointG2::BASE * x
38
- yg = BLS::PointG1::BASE * y
35
+ xg2 = x.value.zero? ? BLS::PointG2::ZERO : BLS::PointG2::BASE * x
36
+ yg = y.value.zero? ? BLS::PointG1::ZERO : BLS::PointG1::BASE * y
39
37
 
40
38
  # e([commitment - y]^(-1), [1]) * e([proof], [s - x]) = 1
41
39
  lhs =
@@ -48,5 +46,38 @@ module KZG
48
46
  exp = (lhs * rhs).final_exponentiate
49
47
  exp == BLS::Fq12::ONE
50
48
  end
49
+
50
+ # Check a proof for a KZG commitment for an evaluation f(x) = y
51
+ # @param [BLS::PointG1] commit_point
52
+ # @param [BLS::PointG1] proof
53
+ # @param [Array(Integer|BLS::Fr)] x
54
+ # @param [Array(Integer|BLS::Fr)] y
55
+ def valid_multi_proof?(commit_point, proof, x, y)
56
+ x = x.map { |v| v.is_a?(BLS::Fr) ? v.value : v }
57
+ y = y.map { |v| v.is_a?(BLS::Fr) ? v.value : v }
58
+ # compute i(x)
59
+ i_poly = Polynomial.lagrange_interpolate(x, y)
60
+ # compute z(x)
61
+ z_poly = Polynomial.zero_poly(x)
62
+ # e([commitment - interpolation_polynomial(s)]^(-1), [1]) * e([proof], [s^n - x^n]) = 1
63
+ is = Commitment.new(self, i_poly).value
64
+ lhs =
65
+ BLS.pairing(
66
+ (commit_point - is).negate,
67
+ BLS::PointG2::BASE,
68
+ with_final_exp: false
69
+ )
70
+ z_commit =
71
+ z_poly
72
+ .coeffs
73
+ .map
74
+ .with_index do |c, i|
75
+ c.value.zero? ? BLS::PointG2::ZERO : g2_points[i] * c
76
+ end
77
+ .inject(&:+)
78
+ rhs = BLS.pairing(proof, z_commit, with_final_exp: false)
79
+ exp = (lhs * rhs).final_exponentiate
80
+ exp == BLS::Fq12::ONE
81
+ end
51
82
  end
52
83
  end
data/lib/kzg/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module KZG
4
- VERSION = "0.1.0"
4
+ VERSION = "0.3.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kzg
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - azuchi
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-01-25 00:00:00.000000000 Z
11
+ date: 2023-02-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bls12-381
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 0.2.1
19
+ version: 0.2.2
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 0.2.1
26
+ version: 0.2.2
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement