rsa-accumulator 0.1.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6b5bb2ad698c4440d30bdbd29b3be321a3829b78bad6e188d06b351e8d81f337
4
+ data.tar.gz: e9270d41f253c25b4f2a44ca51d4fd03bc8ff323a173b8fff845ba5c8af5ef3c
5
+ SHA512:
6
+ metadata.gz: 3bf39ed19c73847ec804b63032d940e55595f38f6b3e4abce3aba7bceb7524f06bc7a7b015264309e4b2c0123b22c999a110d08bb5982a16790deee658b00bc7
7
+ data.tar.gz: b91fac654230b7f9e5837eb4249881f71e915e3f7911dd63e7bf4065ce8b7daa50bdd8beb0c3ff59283b39ff73972afec66bb4558824ac75918e0b43c1580761
@@ -0,0 +1,22 @@
1
+ name: Ruby
2
+
3
+ on: [push]
4
+
5
+ jobs:
6
+ build:
7
+
8
+ runs-on: ubuntu-latest
9
+ strategy:
10
+ matrix:
11
+ ruby: ['2.5.x', '2.6.x']
12
+ steps:
13
+ - uses: actions/checkout@v1
14
+ - name: Set up Ruby environment
15
+ uses: actions/setup-ruby@v1
16
+ with:
17
+ ruby-version: ${{ matrix.ruby }}
18
+ - name: Build and test with Rake
19
+ run: |
20
+ gem install bundler
21
+ bundle install --jobs 4 --retry 3
22
+ bundle exec rake
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ /Gemfile.lock
10
+ # rspec failure tracking
11
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1 @@
1
+ rsa-accumulator
@@ -0,0 +1 @@
1
+ 2.6.3
@@ -0,0 +1,9 @@
1
+ language: ruby
2
+ addons:
3
+ apt:
4
+ packages:
5
+ - libsodium-dev
6
+ rvm:
7
+ - 2.5.5
8
+ - 2.6.3
9
+ - 2.7.0
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at azuchi@chaintope.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in rsa-acc.gemspec
6
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2019 azuchi
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,68 @@
1
+ # RSA Accumulator for Ruby [![Build Status](https://travis-ci.org/chaintope/rsa-accumulatorrb.svg?branch=master)](https://travis-ci.org/chaintope/rsa-accumulatorrb) [![Gem Version](https://badge.fury.io/rb/rsa-accumulator.svg)](https://badge.fury.io/rb/rsa-accumulator) [![MIT License](http://img.shields.io/badge/license-MIT-blue.svg?style=flat)](LICENSE)
2
+
3
+
4
+ Cryptographic accumulator based on the strong RSA assumption [BBF18](https://eprint.iacr.org/2018/1188.pdf) in Ruby.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'rsa-accumulator'
12
+ ```
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install rsa-accumulator
21
+
22
+ ## Usage
23
+
24
+ ### Setup accumulator
25
+
26
+ First, initialize the accumulator. Since the accumulator uses groups of unknown order, it can be generated in following ways:
27
+
28
+ require 'rsa-accumulator'
29
+
30
+ # using RSA modulus published by RSA Laboratory
31
+ acc = RSA::Accumulator.generate_rsa2048
32
+
33
+ # using Random RSA modulus with a specified bit length(default value is )
34
+ acc = RSA::Accumulator.generate_random(2048)
35
+
36
+ ### Adding elements and membership proof
37
+
38
+ You can add arbitrary String data to the accumulator.
39
+
40
+ acc.add('a', 'b')
41
+ proof = acc.add('c')
42
+
43
+ You can use inclusion proof to prove that an element exists in an accumulator.
44
+
45
+ acc.member?(proof)
46
+
47
+ ### Non membership proof
48
+
49
+ You can generate non-membership proof and prove that the elements does not exist in the accumulator.
50
+
51
+ members = %w(a b)
52
+ non_members = %w(c, d)
53
+ acc.add(*members)
54
+ proof = acc.prove_non_membership(members, non_members)
55
+ acc.non_member?(non_members, proof)
56
+ => true
57
+
58
+ ### Delete element from accumulator
59
+
60
+ You can remove elements from the accumulator by providing the inclusion proof.
61
+
62
+ acc.add('a', 'b')
63
+ proof = acc.add('c')
64
+ acc.delete(proof)
65
+
66
+ acc.member?(proof)
67
+ => false
68
+
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "rsa/accumulator"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,12 @@
1
+ require "rsa/acc/version"
2
+ require 'rsa/acc/ext'
3
+ require 'rsa/acc/functions'
4
+ require 'rsa/acc/proof'
5
+ require 'rsa/acc/poe'
6
+ require 'rsa/acc/poke2'
7
+
8
+ module RSA
9
+ module ACC
10
+ class Error < StandardError; end
11
+ end
12
+ end
@@ -0,0 +1,20 @@
1
+ # Extending an existing class
2
+ module RSA
3
+ module ACC
4
+
5
+ module Ext
6
+
7
+ refine Integer do
8
+ def pow(*several_variants)
9
+ return super(*several_variants) if several_variants.size == 1
10
+ return super(*several_variants) unless several_variants.first.negative?
11
+ exp = several_variants.first
12
+ inv = self.to_bn.mod_inverse(several_variants[1]).to_i
13
+ inv.pow(-exp, several_variants[1])
14
+ end
15
+ end
16
+
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,84 @@
1
+ require 'rbnacl'
2
+
3
+ module RSA
4
+ module ACC
5
+ module Functions
6
+
7
+ using RSA::ACC::Ext
8
+
9
+ # Convert element to prime number.
10
+ # @param [Array[String] elements an element to be converted.
11
+ # @return [Integer] prime number.
12
+ def hash_to_prime(element)
13
+ nonce = 0
14
+ loop do
15
+ candidate = RbNaCl::Hash.blake2b(element + even_hex(nonce)).unpack("C*")
16
+ candidate[-1] |= 1
17
+ candidate = candidate.pack('c*').unpack("H*").first.to_i(16)
18
+ if candidate.to_bn.prime?
19
+ return candidate
20
+ end
21
+ nonce += 1
22
+ end
23
+ end
24
+
25
+ # Converts a list of elements to an product of prime numbers.
26
+ # @param [Array[String]] elements a list of element.
27
+ # @return [Integer] an product of prime numbers
28
+ def elements_to_prime(elements)
29
+ elements.map{|e|hash_to_prime(e)}.inject(:*)
30
+ end
31
+
32
+ # Computes (xy) th root of g given xth and yth roots of g. x and y is co-prime.
33
+ # (a, b) ← Bezout(x, y)
34
+ #
35
+ # @param [Integer] w1 first witness.
36
+ # @param [Integer] w2 second witness.
37
+ # @param [Integer] x
38
+ # @param [Integer] y
39
+ # @return [Integer] w1^b * w2^a
40
+ def shamir_trick(w1, w2, x, y, modulus)
41
+ raise ArgumentError, 'w1^x != w2^y' unless w1.pow(x, modulus) == w2.pow(y, modulus)
42
+ a, b = egcd(x, y)
43
+ raise ArgumentError, 'Inputs does not co-prime.' unless a * x + b * y == 1
44
+ (w1.pow(b, modulus) * w2.pow(a, modulus)) % modulus
45
+ end
46
+
47
+ # Computes Bezout coefficients.
48
+ # see: https://github.com/dryruby/rsa.rb/blob/b1366970d31dba0078fd06d9f5d3ddd4952fb087/lib/rsa/math.rb#L143
49
+ # @param [Integer] x
50
+ # @param [Integer] y
51
+ # @return [Array[Integer, Integer]] Bezout coefficients
52
+ def egcd(x, y)
53
+ return [0, 1] if x.modulo(y).zero?
54
+ a, b = egcd(y, x.modulo(y))
55
+ [b, a - b * x.div(y)]
56
+ end
57
+
58
+ # Computes a challenge from +params+.
59
+ # @param [Array[Integer]] params
60
+ # @return [Integer] prime number of challenge.
61
+ def compute_challenge(*params)
62
+ hash_to_prime(params.map{|p|even_hex(p)}.join)
63
+ end
64
+
65
+ # Computes hash value from +params+.
66
+ # @param [Array[Integer]] params
67
+ # @return [Integer] hash value.
68
+ def blake2_hash(*params)
69
+ RbNaCl::Hash.blake2b(params.map{|p|even_hex(p)}.join).unpack("H*").first.to_i(16)
70
+ end
71
+
72
+ private
73
+
74
+ # Convert +num+ to even hex string.
75
+ # @param [Integer] num
76
+ # @return [String] hex string.
77
+ def even_hex(num)
78
+ hex = num.to_s(16)
79
+ hex.rjust((hex.length / 2.0).ceil * 2, '0')
80
+ end
81
+
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,41 @@
1
+ module RSA
2
+ module ACC
3
+
4
+ # Non-Interactive Proof of Exponentiation
5
+ module PoE
6
+
7
+ using RSA::ACC::Ext
8
+
9
+ include RSA::ACC::Functions
10
+ extend RSA::ACC::Functions
11
+
12
+ module_function
13
+
14
+ # Computes a proof +base+ ^ H(+exp+) was performed to derive +result+.
15
+ # @param [Integer] base The known base.
16
+ # @param [Integer] exp The exponentiation.
17
+ # @param [Integer] result such as result = base^exp.
18
+ # @param [Integer] modulus modulus using computation.
19
+ def prove(base, exp, result, modulus)
20
+ l = compute_challenge(base, exp, result)
21
+ q = exp / l
22
+ base.pow(q, modulus)
23
+ end
24
+
25
+ # Verifies that base^exp = result using the given proof to avoid computation.
26
+ # @param [Integer] base The known base.
27
+ # @param [Integer] exp The exponentiation.
28
+ # @param [Integer] result such as result = base^exp.
29
+ # @param [Integer] proof an proof.
30
+ # @param [Integer] modulus modulus using computation.
31
+ def verify(base, exp, result, proof, modulus)
32
+ l = compute_challenge(base, exp, result)
33
+ r = exp % l
34
+ w = (proof.pow(l, modulus) * base.pow(r, modulus)) % modulus
35
+ w == result
36
+ end
37
+
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,71 @@
1
+ module RSA
2
+ module ACC
3
+
4
+ class PoKE2Proof
5
+
6
+ using RSA::ACC::Ext
7
+
8
+ attr_reader :z
9
+ attr_reader :q
10
+ attr_reader :r
11
+
12
+ def initialize(z, q, r)
13
+ @z = z
14
+ @q = q
15
+ @r = r
16
+ end
17
+
18
+ # Check whether same proof.
19
+ # @param [RSA::ACC::PoKE2Proof] other other proof.
20
+ # @return [Boolean] whether same proof.
21
+ def ==(other)
22
+ return false unless other.is_a?(RSA::ACC::PoKE2Proof)
23
+ z == other.z && q == other.q && r == other.r
24
+ end
25
+
26
+ end
27
+
28
+ # Non-Interactive Proof of knowledge of exponent2.
29
+ module PoKE2
30
+
31
+ using RSA::ACC::Ext
32
+
33
+ include RSA::ACC::Functions
34
+ extend RSA::ACC::Functions
35
+
36
+ module_function
37
+
38
+ # Computes a proof that you know +exp+ s.t. +base+ ^ +exp+ = +result+.
39
+ # @param [Integer] base
40
+ # @param [Integer] exp
41
+ # @param [Integer] result
42
+ # @param [Integer] modulus
43
+ # @return [RSA::ACC::PoKE2Proof] a proof.
44
+ def prove(base, exp, result, modulus)
45
+ g = RSA::Accumulator::RSA2048_UNKNOWN_ELEM
46
+ z = g.pow(exp, modulus)
47
+ l = compute_challenge(base, result, z)
48
+ alpha = blake2_hash(base, result, z, l)
49
+ q, r = exp.divmod(l)
50
+ RSA::ACC::PoKE2Proof.new(z, ((base * g.pow(alpha, modulus)) % modulus).pow(q, modulus), r)
51
+ end
52
+
53
+ # Verifies that the prover knows +exp+ s.t. +base+ ^ +exp+ = +result+
54
+ # @param [Integer] base
55
+ # @param [Integer] result
56
+ # @param [RSA::ACC::PoKE2Proof] proof
57
+ # @param [Integer] modulus
58
+ # @return [Boolean] Returns true for successful verification, false otherwise.
59
+ def verify(base, result, proof, modulus)
60
+ g = RSA::Accumulator::RSA2048_UNKNOWN_ELEM
61
+ l = compute_challenge(base, result, proof.z)
62
+ alpha = blake2_hash(base, result, proof.z, l)
63
+ lhs = (proof.q.pow(l, modulus) * ((base * g.pow(alpha, modulus) % modulus)).pow(proof.r, modulus)) % modulus
64
+ rhs = (result * proof.z.pow(alpha, modulus) % modulus)
65
+ lhs == rhs
66
+ end
67
+
68
+ end
69
+
70
+ end
71
+ end
@@ -0,0 +1,51 @@
1
+ module RSA
2
+ module ACC
3
+
4
+ # Proof of membership of the element's inclusion in the accumulator.
5
+ class MembershipProof
6
+
7
+ include Functions
8
+
9
+ # witness^H(element) == acc
10
+ attr_reader :element
11
+ attr_reader :witness
12
+ attr_reader :acc_value
13
+ attr_reader :proof # prof calculated by PoE
14
+
15
+ def initialize(element, witness, acc_value, proof)
16
+ @element = element
17
+ @witness = witness
18
+ @acc_value = acc_value
19
+ @proof = proof
20
+ end
21
+
22
+ # Convert element to prime number.
23
+ # @return [Integer] prime number of element.
24
+ def element_prime
25
+ return nil if element.nil?
26
+ element.is_a?(Array) ? elements_to_prime(element) : hash_to_prime(element)
27
+ end
28
+
29
+ end
30
+
31
+ # Proof of non-membership of the element's not inclusion in the accumulator.
32
+ class NonMembershipProof
33
+
34
+ attr_reader :d # d = g^b
35
+ attr_reader :v # v = A(current acc)^a
36
+ attr_reader :gv_inv # gv_inv = v^{-1}
37
+ attr_reader :poke2_proof # NI-PoKE2(A, v, a)
38
+ attr_reader :poe_proof # NI-PoE(d, x, g*v^{-1})
39
+
40
+ def initialize(d, v, gv_inv, poke2_proof, poe_proof)
41
+ @d = d
42
+ @v = v
43
+ @gv_inv = gv_inv
44
+ @poke2_proof = poke2_proof
45
+ @poe_proof = poe_proof
46
+ end
47
+
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,5 @@
1
+ module RSA
2
+ module ACC
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,141 @@
1
+ require 'rsa/acc'
2
+ require 'openssl'
3
+ require 'securerandom'
4
+
5
+ module RSA
6
+ class Accumulator
7
+
8
+ using RSA::ACC::Ext
9
+
10
+ include RSA::ACC::Functions
11
+ include RSA::ACC::PoE
12
+
13
+ # RSA-2048 modulus(https://en.wikipedia.org/wiki/RSA_numbers#RSA-2048).
14
+ RSA2048_MODULUS = 25195908475657893494027183240048398571429282126204032027777137836043662020707595556264018525880784406918290641249515082189298559149176184502808489120072844992687392807287776735971418347270261896375014971824691165077613379859095700097330459748808428401797429100642458691817195118746121515172654632282216869987549182422433637259085141865462043576798423387184774447920739934236584823824281198163815010674810451660377306056201619676256133844143603833904414952634432190114657544454178424020924616515723350778707749817125772467962926386356373289912154831438167899885040445364023527381951378636564391212010397122822120720357
15
+ RSA2048_UNKNOWN_ELEM = 2
16
+
17
+ attr_reader :n
18
+ attr_accessor :value
19
+ attr_reader :g # Initial value
20
+
21
+ # Generate accumulator using RSA2048 modulus.
22
+ # @return [RSA::Accumulator]
23
+ def self.generate_rsa2048
24
+ new(RSA2048_MODULUS, RSA2048_UNKNOWN_ELEM)
25
+ end
26
+
27
+ # Generate accumulator with random modulus.
28
+ # @param [Integer] bit_length bit length of accumulator. Default: 3072 bits.
29
+ # @return [RSA::Accumulator]
30
+ def self.generate_random(bit_length = 3072)
31
+ n = OpenSSL::PKey::RSA.generate(bit_length).n.to_i
32
+ new(n, SecureRandom.random_number(n))
33
+ end
34
+
35
+ # Initialize accumulator
36
+ # @param [Integer] n modulus
37
+ # @param [Integer] value initial value
38
+ # @return [RSA::Accumulator]
39
+ def initialize(n, value)
40
+ @n = n
41
+ @value = value
42
+ @g = value
43
+ end
44
+
45
+ # Add element to accumulator and get inclusion proof.
46
+ # @param [Array[String]] elements a list of elements to be added.
47
+ # @return [RSA::ACC::MembershipProof] inclusion proof.
48
+ def add(*elements)
49
+ current_acc = value
50
+ p = elements_to_prime(elements)
51
+ @value = value.pow(p, n)
52
+ RSA::ACC::MembershipProof.new(elements, current_acc, value, RSA::ACC::PoE.prove(current_acc, p, value, n))
53
+ end
54
+
55
+ # Check whether +other+ is same accumulator.
56
+ # @param [RSA::ACC:Accumulator] other other accumulator.
57
+ # @return [Boolean] if same acc return true, otherwise return false.
58
+ def ==(other)
59
+ return false unless other.is_a?(Accumulator)
60
+ self.n == other.n && self.value == other.value
61
+ end
62
+
63
+ # Check whether +proof+#element include in accumulator.
64
+ # @param [RSA::ACC::MembershipProof] proof inclusion proof.
65
+ # @return [Boolean] If element exist in acc return true, otherwise false.
66
+ def member?(proof)
67
+ RSA::ACC::PoE.verify(proof.witness, proof.element_prime, value, proof.proof, n)
68
+ end
69
+
70
+ # Verifies a non-membership proof against the current accumulator and +elements+ whose non-inclusion is being proven.
71
+ # @param [Array[String]] elements elements whose non-inclusion is being proven.
72
+ # @param [RSA::ACC::NonMembershipProof] proof non-membership proof.
73
+ # @return [Boolean]
74
+ def non_member?(elements, proof)
75
+ x = elements_to_prime(elements)
76
+ RSA::ACC::PoKE2.verify(value, proof.v, proof.poke2_proof, n) &&
77
+ RSA::ACC::PoE.verify(proof.d, x, proof.gv_inv, proof.poe_proof, n)
78
+ end
79
+
80
+ # Generate non-membership proof using set of elements in current acc and non membership elements.
81
+ # @param [Array[String]] members The entire set of elements contained within this accumulator.
82
+ # @param [Array[String]] non_members Elements not included in this accumulator that you want to prove non-membership.
83
+ # @return [RSA::ACC::NonMembershipProof] Non-membership proof.
84
+ def prove_non_membership(members, non_members)
85
+ s = elements_to_prime(members)
86
+ x = elements_to_prime(non_members)
87
+
88
+ a, b = egcd(s, x)
89
+ raise ArgumentError, "Inputs not co-prime." unless a * s + b * x == 1
90
+
91
+ v = value.pow(a, n)
92
+ d = g.pow(b, n)
93
+ gv_inv = (g * v.pow(-1, n)) % n
94
+
95
+ poke2_proof = RSA::ACC::PoKE2.prove(value, a, v, n)
96
+ poe_proof = RSA::ACC::PoE.prove(d, x, gv_inv, n)
97
+
98
+ RSA::ACC::NonMembershipProof.new(d, v, gv_inv, poke2_proof, poe_proof)
99
+ end
100
+
101
+ # Remove the elements in +proofs+ from the accumulator.
102
+ # @param [RSA::ACC::MembershipProof] proofs proofs including the elements to be removed and the witnesses.
103
+ # @return [RSA::ACC::MembershipProof] Proof that the accumulator before the remove contained the deleted elements.
104
+ def delete(*proofs)
105
+ return RSA::ACC::MembershipProof.new(proofs.map(&:element).flatten, value, value, RSA::ACC::PoE.prove(value, 1, value, n)) if proofs.empty?
106
+
107
+ witnesses = proofs.map do |proof|
108
+ p = proof.element_prime
109
+ raise RSA::ACC::Error, 'Bad witness.' unless proof.witness.pow(p, n) == value
110
+ [p, proof.witness]
111
+ end
112
+
113
+ current_value = value
114
+ proof_product = witnesses.first[0]
115
+ new_value = witnesses.first[1]
116
+ if witnesses.size > 1
117
+ witnesses[1..-1].each do |w|
118
+ new_value = shamir_trick(new_value, w[1], proof_product, w[0], n)
119
+ proof_product *= w[0]
120
+ end
121
+ end
122
+
123
+ @value = new_value
124
+ RSA::ACC::MembershipProof.new(proofs.map{|p|p.element}.flatten, value, current_value, RSA::ACC::PoE.prove(value, proof_product, current_value, n))
125
+ end
126
+
127
+ # Computes an xi-th root of +y+ for all i = 1, ..., n in total time O(n log(n)).
128
+ # @param [Array[Integer]] f factorizations of the exponent x = x1, ..., xn.
129
+ # @return [Array{Integer}] array of xi-th root
130
+ def root_factor(*f)
131
+ return [value] if f.size == 1
132
+ half_n = f.size / 2
133
+ g_l = RSA::Accumulator.new(n, value.pow(f[0...half_n].map.inject(:*), n))
134
+ g_r = RSA::Accumulator.new(n, value.pow(f[half_n..-1].map.inject(:*), n))
135
+ l = g_r.root_factor(*f[0...half_n])
136
+ r = g_l.root_factor(*f[half_n..-1])
137
+ [l, r].flatten
138
+ end
139
+
140
+ end
141
+ end
@@ -0,0 +1,31 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "rsa/acc/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "rsa-accumulator"
8
+ spec.version = RSA::ACC::VERSION
9
+ spec.authors = ["azuchi"]
10
+ spec.email = ["azuchi@chaintope.com"]
11
+
12
+ spec.summary = %q{RSA accumulator implementation for Ruby.}
13
+ spec.description = %q{RSA accumulator implementation for Ruby.}
14
+ spec.homepage = "https://github.com/chaintope/rsa-accumulatorrb"
15
+ spec.license = "MIT"
16
+
17
+ # Specify which files should be added to the gem when it is released.
18
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
19
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
20
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
21
+ end
22
+ spec.bindir = "exe"
23
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
+ spec.require_paths = ["lib"]
25
+
26
+ spec.add_runtime_dependency "rbnacl"
27
+
28
+ spec.add_development_dependency "bundler"
29
+ spec.add_development_dependency "rake", ">= 12.3.3"
30
+ spec.add_development_dependency "rspec", "~> 3.0"
31
+ end
metadata ADDED
@@ -0,0 +1,121 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rsa-accumulator
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - azuchi
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-06-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rbnacl
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 12.3.3
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 12.3.3
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ description: RSA accumulator implementation for Ruby.
70
+ email:
71
+ - azuchi@chaintope.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".github/workflows/ruby.yml"
77
+ - ".gitignore"
78
+ - ".rspec"
79
+ - ".ruby-gemset"
80
+ - ".ruby-version"
81
+ - ".travis.yml"
82
+ - CODE_OF_CONDUCT.md
83
+ - Gemfile
84
+ - LICENSE.txt
85
+ - README.md
86
+ - Rakefile
87
+ - bin/console
88
+ - bin/setup
89
+ - lib/rsa/acc.rb
90
+ - lib/rsa/acc/ext.rb
91
+ - lib/rsa/acc/functions.rb
92
+ - lib/rsa/acc/poe.rb
93
+ - lib/rsa/acc/poke2.rb
94
+ - lib/rsa/acc/proof.rb
95
+ - lib/rsa/acc/version.rb
96
+ - lib/rsa/accumulator.rb
97
+ - rsa-accumulatorrb.gemspec
98
+ homepage: https://github.com/chaintope/rsa-accumulatorrb
99
+ licenses:
100
+ - MIT
101
+ metadata: {}
102
+ post_install_message:
103
+ rdoc_options: []
104
+ require_paths:
105
+ - lib
106
+ required_ruby_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ required_rubygems_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ requirements: []
117
+ rubygems_version: 3.0.3
118
+ signing_key:
119
+ specification_version: 4
120
+ summary: RSA accumulator implementation for Ruby.
121
+ test_files: []