ed25519 1.0.0-jruby

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.rspec +5 -0
  4. data/.rubocop.yml +35 -0
  5. data/.travis.yml +13 -0
  6. data/CHANGES.md +16 -0
  7. data/CODE_OF_CONDUCT.md +74 -0
  8. data/Gemfile +12 -0
  9. data/LICENSE +22 -0
  10. data/README.md +159 -0
  11. data/Rakefile +27 -0
  12. data/ed25519.gemspec +32 -0
  13. data/ed25519.png +0 -0
  14. data/ext/ed25519_java/org/cryptosphere/ed25519.java +228 -0
  15. data/ext/ed25519_ref10/api.h +4 -0
  16. data/ext/ed25519_ref10/base.h +1344 -0
  17. data/ext/ed25519_ref10/base2.h +40 -0
  18. data/ext/ed25519_ref10/d.h +1 -0
  19. data/ext/ed25519_ref10/d2.h +1 -0
  20. data/ext/ed25519_ref10/ed25519_ref10.c +99 -0
  21. data/ext/ed25519_ref10/ed25519_ref10.h +33 -0
  22. data/ext/ed25519_ref10/extconf.rb +9 -0
  23. data/ext/ed25519_ref10/fe.h +56 -0
  24. data/ext/ed25519_ref10/fe_0.c +19 -0
  25. data/ext/ed25519_ref10/fe_1.c +19 -0
  26. data/ext/ed25519_ref10/fe_add.c +57 -0
  27. data/ext/ed25519_ref10/fe_cmov.c +63 -0
  28. data/ext/ed25519_ref10/fe_copy.c +29 -0
  29. data/ext/ed25519_ref10/fe_frombytes.c +71 -0
  30. data/ext/ed25519_ref10/fe_invert.c +14 -0
  31. data/ext/ed25519_ref10/fe_isnegative.c +16 -0
  32. data/ext/ed25519_ref10/fe_isnonzero.c +19 -0
  33. data/ext/ed25519_ref10/fe_mul.c +252 -0
  34. data/ext/ed25519_ref10/fe_neg.c +45 -0
  35. data/ext/ed25519_ref10/fe_pow22523.c +13 -0
  36. data/ext/ed25519_ref10/fe_sq.c +148 -0
  37. data/ext/ed25519_ref10/fe_sq2.c +159 -0
  38. data/ext/ed25519_ref10/fe_sub.c +57 -0
  39. data/ext/ed25519_ref10/fe_tobytes.c +119 -0
  40. data/ext/ed25519_ref10/ge.h +95 -0
  41. data/ext/ed25519_ref10/ge_add.c +11 -0
  42. data/ext/ed25519_ref10/ge_add.h +97 -0
  43. data/ext/ed25519_ref10/ge_double_scalarmult.c +96 -0
  44. data/ext/ed25519_ref10/ge_frombytes.c +50 -0
  45. data/ext/ed25519_ref10/ge_madd.c +11 -0
  46. data/ext/ed25519_ref10/ge_madd.h +88 -0
  47. data/ext/ed25519_ref10/ge_msub.c +11 -0
  48. data/ext/ed25519_ref10/ge_msub.h +88 -0
  49. data/ext/ed25519_ref10/ge_p1p1_to_p2.c +12 -0
  50. data/ext/ed25519_ref10/ge_p1p1_to_p3.c +13 -0
  51. data/ext/ed25519_ref10/ge_p2_0.c +8 -0
  52. data/ext/ed25519_ref10/ge_p2_dbl.c +11 -0
  53. data/ext/ed25519_ref10/ge_p2_dbl.h +73 -0
  54. data/ext/ed25519_ref10/ge_p3_0.c +9 -0
  55. data/ext/ed25519_ref10/ge_p3_dbl.c +12 -0
  56. data/ext/ed25519_ref10/ge_p3_to_cached.c +17 -0
  57. data/ext/ed25519_ref10/ge_p3_to_p2.c +12 -0
  58. data/ext/ed25519_ref10/ge_p3_tobytes.c +14 -0
  59. data/ext/ed25519_ref10/ge_precomp_0.c +8 -0
  60. data/ext/ed25519_ref10/ge_scalarmult_base.c +104 -0
  61. data/ext/ed25519_ref10/ge_sub.c +11 -0
  62. data/ext/ed25519_ref10/ge_sub.h +97 -0
  63. data/ext/ed25519_ref10/ge_tobytes.c +14 -0
  64. data/ext/ed25519_ref10/keypair.c +22 -0
  65. data/ext/ed25519_ref10/open.c +47 -0
  66. data/ext/ed25519_ref10/pow22523.h +160 -0
  67. data/ext/ed25519_ref10/pow225521.h +160 -0
  68. data/ext/ed25519_ref10/sc.h +17 -0
  69. data/ext/ed25519_ref10/sc_muladd.c +366 -0
  70. data/ext/ed25519_ref10/sc_reduce.c +272 -0
  71. data/ext/ed25519_ref10/sha512.c +304 -0
  72. data/ext/ed25519_ref10/sha512.h +8 -0
  73. data/ext/ed25519_ref10/sign.c +41 -0
  74. data/ext/ed25519_ref10/sqrtm1.h +1 -0
  75. data/ext/ed25519_ref10/verify.c +40 -0
  76. data/lib/ed25519.rb +65 -0
  77. data/lib/ed25519/provider/jruby.rb +39 -0
  78. data/lib/ed25519/signing_key.rb +39 -0
  79. data/lib/ed25519/verify_key.rb +44 -0
  80. data/lib/ed25519/version.rb +5 -0
  81. data/lib/ed25519_java.jar +0 -0
  82. metadata +138 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7ae17b8d776a0e09bfba306d42f817e806cdeb14
4
+ data.tar.gz: f7551dd72b2361acc584c0e8a7f8406f1a395532
5
+ SHA512:
6
+ metadata.gz: c4997f60634446a3b948b9ddcd2c228b2d2a4ce2a23ef9cb5f09b933d090273b898c3e97c802cad9c4f85710ed4b588aac9f414f9aa2a01699bcd48f5aaded4b
7
+ data.tar.gz: 406ec016f0cdae858fc6276895e36cd3ffc0276b1e1f46ff99b726b33cf7f9daff67ed7e4e21f3b610a6c2e093b7efa591c8d21889736570207b0ef0336b8e9b
@@ -0,0 +1,15 @@
1
+ /Gemfile.lock
2
+ /.bundle/
3
+ /.yardoc
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.o
11
+ *.so
12
+ *.bundle
13
+
14
+ # rspec failure tracking
15
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,5 @@
1
+ --color
2
+ --format documentation
3
+ --order random
4
+ --warnings
5
+ --require spec_helper
@@ -0,0 +1,35 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.4
3
+ DisplayCopNames: true
4
+
5
+ #
6
+ # Style
7
+ #
8
+
9
+ Style/StringLiterals:
10
+ EnforcedStyle: double_quotes
11
+
12
+ #
13
+ # Metrics
14
+ #
15
+
16
+ Metrics/AbcSize:
17
+ Enabled: false
18
+
19
+ Metrics/CyclomaticComplexity:
20
+ Enabled: false
21
+
22
+ Metrics/PerceivedComplexity:
23
+ Enabled: false
24
+
25
+ Metrics/BlockLength:
26
+ Max: 100
27
+
28
+ Metrics/ClassLength:
29
+ Max: 100
30
+
31
+ Metrics/LineLength:
32
+ Max: 128
33
+
34
+ Metrics/MethodLength:
35
+ Max: 25
@@ -0,0 +1,13 @@
1
+ language: ruby
2
+
3
+ rvm:
4
+ - jruby-9.1.15.0
5
+ - 2.2.8
6
+ - 2.3.5
7
+ - 2.4.2
8
+
9
+ before_install: gem install bundler -v 1.16.0
10
+
11
+ branches:
12
+ only:
13
+ - master
@@ -0,0 +1,16 @@
1
+ # [1.0.0] (2017-12-12)
2
+
3
+ [1.0.0]: https://github.com/cryptosphere/x25519/compare/v0.1.0...v1.0.0
4
+
5
+ * [#7](https://github.com/cryptosphere/ed25519/pull/7)
6
+ Keypair refactor
7
+
8
+ * [#6](https://github.com/cryptosphere/ed25519/pull/6)
9
+ Switch from "ref" C implementation to SUPERCOP "ref10"
10
+
11
+ * [#5](https://github.com/cryptosphere/ed25519/pull/5)
12
+ Raise Ed25519::VerifyError if signature verification fails
13
+
14
+ # 0.1.0 (2017-12-11)
15
+
16
+ * Initial release
@@ -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 bascule@gmail.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,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gemspec
6
+
7
+ group :development, :test do
8
+ gem "rake", require: false
9
+ gem "rake-compiler", "~> 1.0", require: false
10
+ gem "rspec", "~> 3.7", require: false
11
+ gem "rubocop", "0.51.0", require: false
12
+ end
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012-2017 Tony Arcieri
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,159 @@
1
+ # ed25519.rb [![Latest Version][gem-shield]][gem-link] [![Build Status][build-image]][build-link] [![Yard Docs][docs-image]][docs-link] [![License: MIT][license-image]][license-link]
2
+
3
+ [gem-shield]: https://badge.fury.io/rb/ed25519.svg
4
+ [gem-link]: https://rubygems.org/gems/ed25519
5
+ [build-image]: https://travis-ci.org/cryptosphere/ed25519.svg?branch=master
6
+ [build-link]: https://travis-ci.org/cryptosphere/ed25519
7
+ [docs-image]: https://img.shields.io/badge/yard-docs-blue.svg
8
+ [docs-link]: http://www.rubydoc.info/gems/ed25519
9
+ [license-image]: https://img.shields.io/badge/license-MIT-blue.svg
10
+ [license-link]: https://github.com/cryptosphere/ed25519/blob/master/LICENSE
11
+
12
+ A Ruby binding to the Ed25519 elliptic curve public-key signature system
13
+ described in [RFC 8032].
14
+
15
+ Two implementations are provided: a MRI C extension which uses the "ref10"
16
+ implementation from the SUPERCOP benchmark suite, and a pure Java version
17
+ which is a direct port of the Python implementation.
18
+
19
+ [RFC 8032]: https://tools.ietf.org/html/rfc8032
20
+
21
+ ## What is Ed25519?
22
+
23
+ Ed25519 is a modern implementation of a [Schnorr signature] system using
24
+ elliptic curve groups.
25
+
26
+ Ed25519 provides a 128-bit security level, that is to say, all known attacks
27
+ take at least 2^128 operations, providing the same security level as AES-128,
28
+ NIST P-256, and RSA-3072.
29
+
30
+ ![Ed25519 Diagram](https://raw.github.com/cryptosphere/ed25519/master/ed25519.png)
31
+
32
+ Ed25519 has a number of unique properties that make it one of the best-in-class
33
+ digital signature algorithms:
34
+
35
+ * ***Small keys***: Ed25519 keys are only 256-bits (32 bytes), making them
36
+ small enough to easily copy around. Ed25519 also allows the public key
37
+ to be derived from the private key, meaning that it doesn't need to be
38
+ included in a serialized private key in cases you want both.
39
+ * ***Small signatures***: Ed25519 signatures are only 512-bits (64 bytes),
40
+ one of the smallest signature sizes available.
41
+ * ***Deterministic***: Unlike (EC)DSA, Ed25519 does not rely on an entropy
42
+ source when signing messages. This can be a potential attack vector if
43
+ the entropy source is not generating good random numbers. Ed25519 avoids
44
+ this problem entirely and will always generate the same signature for the
45
+ same data.
46
+ * ***Collision Resistant***: Hash-function collisions do not break this
47
+ system. This adds a layer of defense against the possibility of weakness
48
+ in the selected hash function.
49
+
50
+ You can read more on [Dan Bernstein's Ed25519 site](http://ed25519.cr.yp.to/).
51
+
52
+ [Schnorr signature]: https://en.wikipedia.org/wiki/Schnorr_signature
53
+
54
+ ## Installation
55
+
56
+ Add this line to your application's Gemfile:
57
+
58
+ gem 'ed25519'
59
+
60
+ And then execute:
61
+
62
+ $ bundle
63
+
64
+ Or install it yourself as:
65
+
66
+ $ gem install ed25519
67
+
68
+ # Usage
69
+
70
+ Require **ed25519.rb** in your Ruby program:
71
+
72
+ ```ruby
73
+ require "ed25519"
74
+ ```
75
+
76
+ Generate a new random signing key:
77
+
78
+ ```ruby
79
+ signing_key = Ed25519::SigningKey.generate
80
+ ```
81
+
82
+ Sign a message with the signing key:
83
+
84
+ ```ruby
85
+ signature = signing_key.sign(message)
86
+ ```
87
+
88
+ Obtain the verify key for a given signing key:
89
+
90
+ ```ruby
91
+ verify_key = signing_key.verify_key
92
+ ```
93
+
94
+ Check the validity of a signature:
95
+
96
+ ```ruby
97
+ verify_key.verify(signature, message)
98
+ ```
99
+
100
+ The verify method will return `true` if the signature verifies, or raise
101
+ `Ed25519::VerifyError` if verification fails.
102
+
103
+ ### Serializing Keys
104
+
105
+ Keys can be serialized as 32-byte binary strings as follows:
106
+
107
+ ```ruby
108
+ signature_key_bytes = signing_key.to_bytes
109
+ verify_key_bytes = verify_key.to_bytes
110
+ ```
111
+
112
+ The binary serialization can be passed directly into the constructor for a given key type:
113
+
114
+ ```ruby
115
+ signing_key = Ed25519::SigningKey.new(signature_key_bytes)
116
+ verify_key = Ed25519::VerifyKey.new(verify_key_bytes)
117
+ ```
118
+
119
+ ## Security Notes
120
+
121
+ The Ed25519 "ref" implementation from SUPERCOP was lovingly crafted by expert
122
+ security boffins with great care taken to prevent timing attacks. The same
123
+ cannot be said for the C code used in the **ed25519.rb** C extension or in the
124
+ entirety of the provided Java implementation.
125
+
126
+ Care should be taken to avoid leaking to the attacker how long it takes to
127
+ generate keys or sign messages (at least until **ed25519.rb** itself can be audited
128
+ by experts who can fix any potential timing vulnerabilities)
129
+
130
+ **ed25519.rb** relies on a strong `SecureRandom` for key generation.
131
+ Weaknesses in the random number source can potentially result in insecure keys.
132
+
133
+ ## JRuby Notes
134
+
135
+ **ed25519.rb** provides a pure Java backend, however this backend is much slower
136
+ than the C-based version. While **ed25519.rb** will function on JRuby, it may be
137
+ too slow to be usable for a given use case. You should benchmark your
138
+ application to determine if it will be fast enough for your purposes.
139
+
140
+ ## Contributing
141
+
142
+ Bug reports and pull requests are welcome on GitHub at https://github.com/cryptosphere/ed25519.
143
+ This project is intended to be a safe, welcoming space for collaboration,
144
+ and contributors areexpected to adhere to the [Contributor Covenant](http://contributor-covenant.org)
145
+ code of conduct.
146
+
147
+ ## License
148
+
149
+ Copyright (c) 2012-2017 Tony Arcieri. Distributed under the MIT License. See
150
+ [LICENSE] for further details.
151
+
152
+ [LICENSE]: https://github.com/cryptosphere/ed25519/blob/master/LICENSE
153
+
154
+ ## Code of Conduct
155
+
156
+ Everyone interacting in the **ed25519.rb** project’s codebases, issue trackers, chat
157
+ rooms and mailing lists is expected to follow the [code of conduct].
158
+
159
+ [code of conduct]: https://github.com/cryptosphere/ed25519/blob/master/CODE_OF_CONDUCT.md
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+
5
+ require "rake/clean"
6
+ CLEAN.include("**/*.o", "**/*.so", "**/*.bundle", "pkg", "tmp")
7
+
8
+ if defined? JRUBY_VERSION
9
+ require "rake/javaextensiontask"
10
+ Rake::JavaExtensionTask.new("ed25519_java") do |ext|
11
+ ext.ext_dir = "ext/ed25519_java"
12
+ end
13
+ else
14
+ require "rake/extensiontask"
15
+
16
+ Rake::ExtensionTask.new("ed25519_ref10") do |ext|
17
+ ext.ext_dir = "ext/ed25519_ref10"
18
+ end
19
+ end
20
+
21
+ require "rspec/core/rake_task"
22
+ RSpec::Core::RakeTask.new
23
+
24
+ require "rubocop/rake_task"
25
+ RuboCop::RakeTask.new
26
+
27
+ task default: %w[compile spec rubocop]
@@ -0,0 +1,32 @@
1
+
2
+ # frozen_string_literal: true
3
+
4
+ require File.expand_path("lib/ed25519/version", __dir__)
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "ed25519"
8
+ spec.version = Ed25519::VERSION
9
+ spec.authors = ["Tony Arcieri"]
10
+ spec.email = ["tony.arcieri@gmail.com"]
11
+ spec.summary = "An efficient digital signature library providing the Ed25519 algorithm"
12
+ spec.description = <<-DESCRIPTION.strip.gsub(/\s+/, " ")
13
+ A Ruby binding to the Ed25519 elliptic curve public-key signature system
14
+ described in RFC 8032.
15
+ DESCRIPTION
16
+ spec.homepage = "https://github.com/cryptosphere/ed25519"
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ if defined? JRUBY_VERSION
23
+ spec.platform = "jruby"
24
+ spec.files << "lib/ed25519_java.jar"
25
+ else
26
+ spec.platform = Gem::Platform::RUBY
27
+ spec.extensions = ["ext/ed25519_ref10/extconf.rb"]
28
+ end
29
+
30
+ spec.required_ruby_version = ">= 2.2.2"
31
+ spec.add_development_dependency "bundler", "~> 1.16"
32
+ end
Binary file
@@ -0,0 +1,228 @@
1
+ package org.cryptosphere;
2
+
3
+ import java.math.BigInteger;
4
+ import java.nio.ByteBuffer;
5
+ import java.security.MessageDigest;
6
+ import java.security.NoSuchAlgorithmException;
7
+ import java.util.Arrays;
8
+
9
+ /* Written by k3d3
10
+ * Released to the public domain
11
+ */
12
+
13
+ public class ed25519 {
14
+ static final int b = 256;
15
+ static final BigInteger q = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564819949");
16
+ static final BigInteger qm2 = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564819947");
17
+ static final BigInteger qp3 = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564819952");
18
+ static final BigInteger l = new BigInteger("7237005577332262213973186563042994240857116359379907606001950938285454250989");
19
+ static final BigInteger d = new BigInteger("-4513249062541557337682894930092624173785641285191125241628941591882900924598840740");
20
+ static final BigInteger I = new BigInteger("19681161376707505956807079304988542015446066515923890162744021073123829784752");
21
+ static final BigInteger By = new BigInteger("46316835694926478169428394003475163141307993866256225615783033603165251855960");
22
+ static final BigInteger Bx = new BigInteger("15112221349535400772501151409588531511454012693041857206046113283949847762202");
23
+ static final BigInteger[] B = {Bx.mod(q),By.mod(q)};
24
+ static final BigInteger un = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564819967");
25
+
26
+ static byte[] H(byte[] m) {
27
+ MessageDigest md;
28
+ try {
29
+ md = MessageDigest.getInstance("SHA-512");
30
+ md.reset();
31
+ return md.digest(m);
32
+ } catch (NoSuchAlgorithmException e) {
33
+ e.printStackTrace();
34
+ System.exit(1);
35
+ }
36
+ return null;
37
+ }
38
+
39
+ static BigInteger expmod(BigInteger b, BigInteger e, BigInteger m) {
40
+ //System.out.println("expmod open with b=" + b + " e=" + e + " m=" + m);
41
+ if (e.equals(BigInteger.ZERO)) {
42
+ //System.out.println("expmod close with 1z");
43
+ return BigInteger.ONE;
44
+ }
45
+ BigInteger t = expmod(b, e.divide(BigInteger.valueOf(2)), m).pow(2).mod(m);
46
+ //System.out.println("expmod 1/2 t="+t+" e="+e+" testbit="+(e.testBit(0)?1:0));
47
+ if (e.testBit(0)) {
48
+ t = t.multiply(b).mod(m);
49
+ }
50
+ //System.out.println("expmod close with " + t);
51
+ return t;
52
+ }
53
+
54
+ static BigInteger inv(BigInteger x) {
55
+ //System.out.println("inv open with " + x);
56
+ //System.out.println("inv close with " + expmod(x, qm2, q));
57
+ return expmod(x, qm2, q);
58
+ }
59
+
60
+ static BigInteger xrecover(BigInteger y) {
61
+ BigInteger y2 = y.multiply(y);
62
+ BigInteger xx = (y2.subtract(BigInteger.ONE)).multiply(inv(d.multiply(y2).add(BigInteger.ONE)));
63
+ BigInteger x = expmod(xx, qp3.divide(BigInteger.valueOf(8)), q);
64
+ if (!x.multiply(x).subtract(xx).mod(q).equals(BigInteger.ZERO)) x = (x.multiply(I).mod(q));
65
+ if (!x.mod(BigInteger.valueOf(2)).equals(BigInteger.ZERO)) x = q.subtract(x);
66
+ return x;
67
+ }
68
+
69
+ static BigInteger[] edwards(BigInteger[] P, BigInteger[] Q) {
70
+ BigInteger x1 = P[0];
71
+ BigInteger y1 = P[1];
72
+ BigInteger x2 = Q[0];
73
+ BigInteger y2 = Q[1];
74
+ BigInteger dtemp = d.multiply(x1).multiply(x2).multiply(y1).multiply(y2);
75
+ //System.out.println("edwards open with "+x1+","+x2+" "+y1+","+y2+" d="+d+" dtemp="+dtemp);
76
+ BigInteger x3 = ((x1.multiply(y2)).add((x2.multiply(y1)))).multiply(inv(BigInteger.ONE.add(dtemp)));
77
+ //System.out.println("edwards 1/2 with "+x1+","+x2+" "+y1+","+y2+" d="+d+" dtemp="+dtemp);
78
+ BigInteger y3 = ((y1.multiply(y2)).add((x1.multiply(x2)))).multiply(inv(BigInteger.ONE.subtract(dtemp)));
79
+ //System.out.println("edwards 2/2 with "+x1+","+x2+" "+y1+","+y2+" d="+d+" dtemp="+dtemp);
80
+ //System.out.println("edwards close with "+x3.mod(q)+","+y3.mod(q));
81
+ return new BigInteger[]{x3.mod(q), y3.mod(q)};
82
+ }
83
+
84
+ static BigInteger[] scalarmult(BigInteger[] P, BigInteger e) {
85
+ //System.out.println("scalarmult open with e = " + e);
86
+ if (e.equals(BigInteger.ZERO)) {
87
+ //System.out.println("scalarmult close with Q = 0,1");
88
+ return new BigInteger[]{BigInteger.ZERO, BigInteger.ONE};
89
+ }
90
+ BigInteger[] Q = scalarmult(P, e.divide(BigInteger.valueOf(2)));
91
+ //System.out.println("scalarmult asQ = " + Q[0] + "," + Q[1]);
92
+ Q = edwards(Q, Q);
93
+ //System.out.println("scalarmult aeQ = " + Q[0] + "," + Q[1] + " e="+e+" testbit="+(e.testBit(0)?1:0));
94
+ if (e.testBit(0)) Q = edwards(Q, P);
95
+ //System.out.println("scalarmult close with Q = " + Q[0] + "," + Q[1]);
96
+ return Q;
97
+ }
98
+
99
+ static byte[] encodeint(BigInteger y) {
100
+ byte[] in = y.toByteArray();
101
+ byte[] out = new byte[in.length];
102
+ for (int i=0;i<in.length;i++) {
103
+ out[i] = in[in.length-1-i];
104
+ }
105
+ return out;
106
+ }
107
+
108
+ static byte[] encodepoint(BigInteger[] P) {
109
+ BigInteger x = P[0];
110
+ BigInteger y = P[1];
111
+ byte[] out = encodeint(y);
112
+ //System.out.println("encodepoint x="+x+" testbit="+(x.testBit(0) ? 1 : 0));
113
+ out[out.length-1] |= (x.testBit(0) ? 0x80 : 0);
114
+ return out;
115
+ }
116
+
117
+ static int bit(byte[] h, int i) {
118
+ //System.out.println("bit open with i="+i);
119
+ //System.out.println("bit close with "+(h[i/8] >> (i%8) & 1));
120
+ return h[i/8] >> (i%8) & 1;
121
+ }
122
+
123
+ static byte[] publickey(byte[] sk) {
124
+ byte[] h = H(sk);
125
+ //System.out.println("publickey open with h=" + test.getHex(h));
126
+ BigInteger a = BigInteger.valueOf(2).pow(b-2);
127
+ for (int i=3;i<(b-2);i++) {
128
+ BigInteger apart = BigInteger.valueOf(2).pow(i).multiply(BigInteger.valueOf(bit(h,i)));
129
+ //System.out.println("publickey apart="+apart);
130
+ a = a.add(apart);
131
+ }
132
+ BigInteger[] A = scalarmult(B,a);
133
+ //System.out.println("publickey close with A="+A[0]+","+A[1]+" out="+test.getHex(encodepoint(A)));
134
+ return encodepoint(A);
135
+ }
136
+
137
+ static BigInteger Hint(byte[] m) {
138
+ byte[] h = H(m);
139
+ BigInteger hsum = BigInteger.ZERO;
140
+ for (int i=0;i<2*b;i++) {
141
+ hsum = hsum.add(BigInteger.valueOf(2).pow(i).multiply(BigInteger.valueOf(bit(h,i))));
142
+ }
143
+ return hsum;
144
+ }
145
+
146
+ static byte[] signature(byte[] m, byte[] sk, byte[] pk) {
147
+ byte[] h = H(sk);
148
+ //System.out.println("signature open with m="+test.getHex(m)+" h="+test.getHex(h)+" pk="+test.getHex(pk));
149
+ BigInteger a = BigInteger.valueOf(2).pow(b-2);
150
+ for (int i=3;i<(b-2);i++) {
151
+ a = a.add(BigInteger.valueOf(2).pow(i).multiply(BigInteger.valueOf(bit(h,i))));
152
+ }
153
+ //System.out.println("signature a="+a);
154
+ ByteBuffer rsub = ByteBuffer.allocate((b/8)+m.length);
155
+ rsub.put(h, b/8, b/4-b/8).put(m);
156
+ //System.out.println("signature rsub="+test.getHex(rsub.array()));
157
+ BigInteger r = Hint(rsub.array());
158
+ //System.out.println("signature r="+r);
159
+ BigInteger[] R = scalarmult(B,r);
160
+ ByteBuffer Stemp = ByteBuffer.allocate(32+pk.length+m.length);
161
+ Stemp.put(encodepoint(R)).put(pk).put(m);
162
+ BigInteger S = r.add(Hint(Stemp.array()).multiply(a)).mod(l);
163
+ ByteBuffer out = ByteBuffer.allocate(64);
164
+ out.put(encodepoint(R)).put(encodeint(S));
165
+ return out.array();
166
+ }
167
+
168
+ static boolean isoncurve(BigInteger[] P) {
169
+ BigInteger x = P[0];
170
+ BigInteger y = P[1];
171
+ //System.out.println("isoncurve open with P="+x+","+y);
172
+ BigInteger xx = x.multiply(x);
173
+ BigInteger yy = y.multiply(y);
174
+ BigInteger dxxyy = d.multiply(yy).multiply(xx);
175
+ //System.out.println("isoncurve close with "+xx.negate().add(yy).subtract(BigInteger.ONE).subtract(dxxyy).mod(q));
176
+ return xx.negate().add(yy).subtract(BigInteger.ONE).subtract(dxxyy).mod(q).equals(BigInteger.ZERO);
177
+ }
178
+
179
+ static BigInteger decodeint(byte[] s) {
180
+ byte[] out = new byte[s.length];
181
+ for (int i=0;i<s.length;i++) {
182
+ out[i] = s[s.length-1-i];
183
+ }
184
+ return new BigInteger(out).and(un);
185
+ }
186
+
187
+ static BigInteger[] decodepoint(byte[] s) throws Exception {
188
+ byte[] ybyte = new byte[s.length];
189
+ for (int i=0;i<s.length;i++) {
190
+ ybyte[i] = s[s.length-1-i];
191
+ }
192
+ //System.out.println("decodepoint open with s="+test.getHex(s)+" ybyte="+test.getHex(ybyte));
193
+ BigInteger y = new BigInteger(ybyte).and(un);
194
+ //System.out.println("decodepoint y="+y);
195
+ BigInteger x = xrecover(y);
196
+ //System.out.println("decodepoint x="+x+" testbit="+(x.testBit(0)?1:0)+" bit="+bit(s, b-1));
197
+ if ((x.testBit(0)?1:0) != bit(s, b-1)) {
198
+ x = q.subtract(x);
199
+ }
200
+ BigInteger[] P = {x,y};
201
+ if (!isoncurve(P)) throw new Exception("decoding point that is not on curve");
202
+ return P;
203
+ }
204
+
205
+ static boolean checkvalid(byte[] s, byte[] m, byte[] pk) throws Exception {
206
+ if (s.length != b/4) throw new Exception("signature length is wrong");
207
+ if (pk.length != b/8) throw new Exception("public-key length is wrong");
208
+ //System.out.println("checkvalid open with s="+test.getHex(s)+" m="+test.getHex(m)+" pk="+test.getHex(pk));
209
+ byte[] Rbyte = Arrays.copyOfRange(s, 0, b/8);
210
+ //System.out.println("checkvalid Rbyte="+test.getHex(Rbyte));
211
+ BigInteger[] R = decodepoint(Rbyte);
212
+ BigInteger[] A = decodepoint(pk);
213
+ //System.out.println("checkvalid R="+R[0]+","+R[1]+" A="+A[0]+","+A[1]);
214
+ byte[] Sbyte = Arrays.copyOfRange(s, b/8, b/4);
215
+ //System.out.println("checkvalid Sbyte="+test.getHex(Sbyte));
216
+ BigInteger S = decodeint(Sbyte);
217
+ //System.out.println("checkvalid S="+S);
218
+ ByteBuffer Stemp = ByteBuffer.allocate(32+pk.length+m.length);
219
+ Stemp.put(encodepoint(R)).put(pk).put(m);
220
+ BigInteger h = Hint(Stemp.array());
221
+ BigInteger[] ra = scalarmult(B,S);
222
+ BigInteger[] rb = edwards(R,scalarmult(A,h));
223
+ //System.out.println("checkvalid ra="+ra[0]+","+ra[1]+" rb="+rb[0]+","+rb[1]);
224
+ if (!ra[0].equals(rb[0]) || !ra[1].equals(rb[1])) // Constant time comparison
225
+ return false;
226
+ return true;
227
+ }
228
+ }