jose 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,52 @@
1
+ module JOSE::JWA::Curve25519_Unsupported
2
+
3
+ extend self
4
+
5
+ def __ruby__?; true; end
6
+ def __supported__?; false; end
7
+
8
+ def ed25519_keypair(secret = nil)
9
+ raise NotImplementedError
10
+ end
11
+
12
+ def ed25519_secret_to_public(sk)
13
+ raise NotImplementedError
14
+ end
15
+
16
+ def ed25519_sign(m, sk)
17
+ raise NotImplementedError
18
+ end
19
+
20
+ def ed25519_verify(sig, m, pk)
21
+ raise NotImplementedError
22
+ end
23
+
24
+ def ed25519ph_keypair(secret = nil)
25
+ raise NotImplementedError
26
+ end
27
+
28
+ def ed25519ph_secret_to_public(sk)
29
+ raise NotImplementedError
30
+ end
31
+
32
+ def ed25519ph_sign(m, sk)
33
+ raise NotImplementedError
34
+ end
35
+
36
+ def ed25519ph_verify(sig, m, pk)
37
+ raise NotImplementedError
38
+ end
39
+
40
+ def x25519_keypair(secret = nil)
41
+ raise NotImplementedError
42
+ end
43
+
44
+ def x25519_secret_to_public(sk)
45
+ raise NotImplementedError
46
+ end
47
+
48
+ def x25519_shared_secret(pk, sk)
49
+ raise NotImplementedError
50
+ end
51
+
52
+ end
@@ -0,0 +1,99 @@
1
+ module JOSE::JWA::Curve448
2
+
3
+ extend self
4
+
5
+ MUTEX = Mutex.new
6
+
7
+ @__implementations__ = []
8
+ @__ruby_implementations__ = []
9
+
10
+ def __implementation__
11
+ return MUTEX.synchronize { @__implementation__ ||= __pick_best_implementation__ }
12
+ end
13
+
14
+ def __implementation__=(implementation)
15
+ return MUTEX.synchronize { @__implementation__ = implementation }
16
+ end
17
+
18
+ def __register__(implementation, ruby = false)
19
+ MUTEX.synchronize {
20
+ if ruby
21
+ @__ruby_implementations__.unshift(implementation)
22
+ else
23
+ @__implementations__.unshift(implementation)
24
+ end
25
+ __config_change__(false)
26
+ implementation
27
+ }
28
+ end
29
+
30
+ def __config_change__(lock = true)
31
+ MUTEX.lock if lock
32
+ @__implementation__ = __pick_best_implementation__ if @__implementation__.nil? or @__implementation__.__ruby__? or not @__implementation__.__supported__?
33
+ MUTEX.unlock if lock
34
+ end
35
+
36
+ def ed448_keypair(secret = nil)
37
+ return (@__implementation__ || __implementation__).ed448_keypair(secret)
38
+ end
39
+
40
+ def ed448_secret_to_public(sk)
41
+ return (@__implementation__ || __implementation__).ed448_secret_to_public(sk)
42
+ end
43
+
44
+ def ed448_sign(m, sk)
45
+ return (@__implementation__ || __implementation__).ed448_sign(m, sk)
46
+ end
47
+
48
+ def ed448_verify(sig, m, pk)
49
+ return (@__implementation__ || __implementation__).ed448_verify(sig, m, pk)
50
+ end
51
+
52
+ def ed448ph_keypair(secret = nil)
53
+ return (@__implementation__ || __implementation__).ed448ph_keypair(secret)
54
+ end
55
+
56
+ def ed448ph_secret_to_public(sk)
57
+ return (@__implementation__ || __implementation__).ed448ph_secret_to_public(sk)
58
+ end
59
+
60
+ def ed448ph_sign(m, sk)
61
+ return (@__implementation__ || __implementation__).ed448ph_sign(m, sk)
62
+ end
63
+
64
+ def ed448ph_verify(sig, m, pk)
65
+ return (@__implementation__ || __implementation__).ed448ph_verify(sig, m, pk)
66
+ end
67
+
68
+ def x448_keypair(secret = nil)
69
+ return (@__implementation__ || __implementation__).x448_keypair(secret)
70
+ end
71
+
72
+ def x448_secret_to_public(sk)
73
+ return (@__implementation__ || __implementation__).x448_secret_to_public(sk)
74
+ end
75
+
76
+ def x448_shared_secret(pk, sk)
77
+ return (@__implementation__ || __implementation__).x448_shared_secret(pk, sk)
78
+ end
79
+
80
+ private
81
+ def __pick_best_implementation__
82
+ implementation = nil
83
+ implementation = @__implementations__.detect do |implementation|
84
+ next implementation.__supported__?
85
+ end
86
+ implementation ||= @__ruby_implementations__.detect do |implementation|
87
+ next implementation.__supported__?
88
+ end
89
+ implementation ||= JOSE::JWA::Curve448_Unsupported
90
+ return implementation
91
+ end
92
+
93
+ end
94
+
95
+ require 'jose/jwa/ed448'
96
+ require 'jose/jwa/x448'
97
+
98
+ require 'jose/jwa/curve448_unsupported'
99
+ require 'jose/jwa/curve448_ruby'
@@ -0,0 +1,54 @@
1
+ module JOSE::JWA::Curve448_Ruby
2
+
3
+ extend self
4
+
5
+ def __ruby__?; true; end
6
+ def __supported__?; JOSE.__crypto_fallback__; end
7
+
8
+ def ed448_keypair(secret = nil)
9
+ return JOSE::JWA::Ed448.keypair(secret)
10
+ end
11
+
12
+ def ed448_secret_to_public(sk)
13
+ return JOSE::JWA::Ed448.sk_to_pk(sk)
14
+ end
15
+
16
+ def ed448_sign(m, sk)
17
+ return JOSE::JWA::Ed448.sign(m, sk)
18
+ end
19
+
20
+ def ed448_verify(sig, m, pk)
21
+ return JOSE::JWA::Ed448.verify(sig, m, pk)
22
+ end
23
+
24
+ def ed448ph_keypair(secret = nil)
25
+ return JOSE::JWA::Ed448.keypair(secret)
26
+ end
27
+
28
+ def ed448ph_secret_to_public(sk)
29
+ return JOSE::JWA::Ed448.sk_to_pk(sk)
30
+ end
31
+
32
+ def ed448ph_sign(m, sk)
33
+ return JOSE::JWA::Ed448.sign_ph(m, sk)
34
+ end
35
+
36
+ def ed448ph_verify(sig, m, pk)
37
+ return JOSE::JWA::Ed448.verify_ph(sig, m, pk)
38
+ end
39
+
40
+ def x448_keypair(secret = nil)
41
+ return JOSE::JWA::X448.keypair(secret)
42
+ end
43
+
44
+ def x448_secret_to_public(sk)
45
+ return JOSE::JWA::X448.sk_to_pk(sk)
46
+ end
47
+
48
+ def x448_shared_secret(pk, sk)
49
+ return JOSE::JWA::X448.shared_secret(pk, sk)
50
+ end
51
+
52
+ end
53
+
54
+ JOSE::JWA::Curve448.__register__(JOSE::JWA::Curve448_Ruby, true)
@@ -0,0 +1,52 @@
1
+ module JOSE::JWA::Curve448_Unsupported
2
+
3
+ extend self
4
+
5
+ def __ruby__?; true; end
6
+ def __supported__?; false; end
7
+
8
+ def ed448_keypair(secret = nil)
9
+ raise NotImplementedError
10
+ end
11
+
12
+ def ed448_secret_to_public(sk)
13
+ raise NotImplementedError
14
+ end
15
+
16
+ def ed448_sign(m, sk)
17
+ raise NotImplementedError
18
+ end
19
+
20
+ def ed448_verify(sig, m, pk)
21
+ raise NotImplementedError
22
+ end
23
+
24
+ def ed448ph_keypair(secret = nil)
25
+ raise NotImplementedError
26
+ end
27
+
28
+ def ed448ph_secret_to_public(sk)
29
+ raise NotImplementedError
30
+ end
31
+
32
+ def ed448ph_sign(m, sk)
33
+ raise NotImplementedError
34
+ end
35
+
36
+ def ed448ph_verify(sig, m, pk)
37
+ raise NotImplementedError
38
+ end
39
+
40
+ def x448_keypair(secret = nil)
41
+ raise NotImplementedError
42
+ end
43
+
44
+ def x448_secret_to_public(sk)
45
+ raise NotImplementedError
46
+ end
47
+
48
+ def x448_shared_secret(pk, sk)
49
+ raise NotImplementedError
50
+ end
51
+
52
+ end
@@ -0,0 +1,117 @@
1
+ module JOSE::JWA::Ed25519
2
+
3
+ extend self
4
+
5
+ C_bits = 256
6
+ C_bytes = (C_bits + 7) / 8
7
+ C_secretbytes = C_bytes
8
+ C_publickeybytes = C_bytes
9
+ C_secretkeybytes = C_secretbytes + C_publickeybytes
10
+ C_signaturebytes = C_bytes + C_bytes
11
+ C_B = JOSE::JWA::Edwards25519Point.stdbase.freeze
12
+
13
+ def secret_to_curve25519(secret)
14
+ raise ArgumentError, "secret must be #{C_secretbytes} bytes" if secret.bytesize != C_secretbytes
15
+ curve25519_scalar = Digest::SHA512.digest(secret)[0, 32]
16
+ curve25519_scalar.setbyte(0, curve25519_scalar.getbyte(0) & 248)
17
+ curve25519_scalar.setbyte(31, (curve25519_scalar.getbyte(31) & 127) | 64)
18
+ return curve25519_scalar
19
+ end
20
+
21
+ def secret_to_pk(secret)
22
+ raise ArgumentError, "secret must be #{C_secretbytes} bytes" if secret.bytesize != C_secretbytes
23
+ return (C_B * OpenSSL::BN.new(secret_to_curve25519(secret).reverse, 2).to_i).encode()
24
+ end
25
+
26
+ def keypair(secret = nil)
27
+ secret ||= SecureRandom.random_bytes(C_secretbytes)
28
+ pk = secret_to_pk(secret)
29
+ sk = secret + pk
30
+ return pk, sk
31
+ end
32
+
33
+ def sk_to_secret(sk)
34
+ raise ArgumentError, "sk must be #{C_secretkeybytes} bytes" if sk.bytesize != C_secretkeybytes
35
+ return sk[0, C_secretbytes]
36
+ end
37
+
38
+ def sk_to_pk(sk)
39
+ raise ArgumentError, "sk must be #{C_secretkeybytes} bytes" if sk.bytesize != C_secretkeybytes
40
+ return sk[C_secretbytes, C_secretkeybytes]
41
+ end
42
+
43
+ def sk_to_curve25519(sk)
44
+ return secret_to_curve25519(sk_to_secret(sk))
45
+ end
46
+
47
+ def pk_to_curve25519(pk)
48
+ raise ArgumentError, "pk must be #{C_publickeybytes} bytes" if pk.bytesize != C_publickeybytes
49
+ a = C_B.decode(pk)
50
+ u = (JOSE::JWA::X25519::C_F_one + a.y) / (JOSE::JWA::X25519::C_F_one - a.y)
51
+ return u.to_bytes(C_bits)
52
+ end
53
+
54
+ def sign(m, sk)
55
+ raise ArgumentError, "sk must be #{C_secretkeybytes} bytes" if sk.bytesize != C_secretkeybytes
56
+ secret, pk = sk[0, 32], sk[32, 64]
57
+ khash = Digest::SHA512.digest(secret)
58
+ curve25519_scalar, seed = khash[0, 32], khash[32, 64]
59
+ curve25519_scalar.setbyte(0, curve25519_scalar.getbyte(0) & 248)
60
+ curve25519_scalar.setbyte(31, (curve25519_scalar.getbyte(31) & 127) | 64)
61
+ a_s = OpenSSL::BN.new(curve25519_scalar.reverse, 2).to_i
62
+ # Calculate r_s and r (r only used in encoded form)
63
+ r_s = (OpenSSL::BN.new(Digest::SHA512.digest(seed+m).reverse, 2) % JOSE::JWA::Edwards25519Point::L).to_i
64
+ r = (C_B * r_s).encode()
65
+ # Calculate h.
66
+ h = (OpenSSL::BN.new(Digest::SHA512.digest(r+pk+m).reverse, 2) % JOSE::JWA::Edwards25519Point::L).to_i
67
+ # Calculate s.
68
+ s = OpenSSL::BN.new((r_s+h*a_s) % JOSE::JWA::Edwards25519Point::L).to_s(2).rjust(C_bytes, JOSE::JWA::ZERO_PAD).reverse
69
+ # The final signature is concatenation of r and s.
70
+ return r+s
71
+ end
72
+
73
+ def sign_ph(m, sk)
74
+ return sign(Digest::SHA512.digest(m), sk)
75
+ end
76
+
77
+ def verify(sig, m, pk)
78
+ # Sanity-check sizes.
79
+ return false if sig.bytesize != C_signaturebytes
80
+ return false if pk.bytesize != C_publickeybytes
81
+ # Split signature into R and S, and parse.
82
+ r, s = sig[0, 32], sig[32, 64]
83
+ r_p, s_s = C_B.decode(r), OpenSSL::BN.new(s.reverse, 2).to_i
84
+ # Parse public key.
85
+ a_p = C_B.decode(pk)
86
+ # Check parse results.
87
+ return false if r_p.nil? or a_p.nil? or s_s > JOSE::JWA::Edwards25519Point::L
88
+ # Calculate h.
89
+ h = (OpenSSL::BN.new(Digest::SHA512.digest(r+pk+m).reverse, 2) % JOSE::JWA::Edwards25519Point::L).to_i
90
+ # Calculate left and right sides of check eq.
91
+ rhs = r_p + (a_p * h)
92
+ lhs = C_B * s_s
93
+ JOSE::JWA::Edwards25519Point::C.times do
94
+ lhs = lhs.double()
95
+ rhs = rhs.double()
96
+ end
97
+ # Check eq. holds?
98
+ return lhs == rhs
99
+ end
100
+
101
+ # def verify(sig, m, pk)
102
+ # return false if sig.bytesize != C_signaturebytes
103
+ # return false if pk.bytesize != C_publickeybytes
104
+ # r, s = sig[0, 32], sig[32, 64]
105
+ # a = C_B.decode(pk)
106
+ # k = (OpenSSL::BN.new(Digest::SHA512.digest(r+pk+m).reverse, 2) % JOSE::JWA::Edwards25519Point::L).to_i
107
+ # s_s = (OpenSSL::BN.new(s.reverse, 2)).to_i
108
+ # lhs = C_B * s_s
109
+ # rhs = C_B.decode(r) + (a * k)
110
+ # return lhs == rhs
111
+ # end
112
+
113
+ def verify_ph(sig, m, pk)
114
+ return verify(sig, Digest::SHA512.digest(m), pk)
115
+ end
116
+
117
+ end
@@ -0,0 +1,36 @@
1
+ module JOSE::JWA::Ed25519_RbNaCl
2
+
3
+ extend self
4
+
5
+ def keypair(secret = nil)
6
+ secret ||= RbNaCl::Random.random_bytes(RbNaCl::Signatures::Ed25519::SEEDBYTES)
7
+ RbNaCl::Util.check_length(secret, RbNaCl::Signatures::Ed25519::SEEDBYTES, "secret")
8
+ pk = RbNaCl::Util.zeros(RbNaCl::Signatures::Ed25519::VERIFYKEYBYTES)
9
+ sk = RbNaCl::Util.zeros(RbNaCl::Signatures::Ed25519::SIGNINGKEYBYTES)
10
+ RbNaCl::Signatures::Ed25519::SigningKey.sign_ed25519_seed_keypair(pk, sk, secret) || fail(RbNaCl::CryptoError, "Failed to generate a key pair")
11
+ return pk, sk
12
+ end
13
+
14
+ def sk_to_pk(sk)
15
+ return sk[RbNaCl::Signatures::Ed25519::VERIFYKEYBYTES..-1]
16
+ end
17
+
18
+ def sign(m, sk)
19
+ signing_key = RbNaCl::Signatures::Ed25519::SigningKey.allocate
20
+ signing_key.instance_variable_set(:@signing_key, sk)
21
+ return signing_key.sign(m)
22
+ end
23
+
24
+ def sign_ph(m, sk)
25
+ return sign(RbNaCl::Hash.sha512(m), sk)
26
+ end
27
+
28
+ def verify(sig, m, pk)
29
+ return RbNaCl::Signatures::Ed25519::VerifyKey.new(pk).verify(sig, m)
30
+ end
31
+
32
+ def verify_ph(sig, m, pk)
33
+ return verify(sig, RbNaCl::Hash.sha512(m), pk)
34
+ end
35
+
36
+ end
@@ -0,0 +1,166 @@
1
+ module JOSE::JWA::Ed448
2
+
3
+ extend self
4
+
5
+ C_bits = 456
6
+ C_bytes = (C_bits + 7) / 8
7
+ C_secretbytes = C_bytes
8
+ C_legacysecretbytes = 32
9
+ C_publickeybytes = C_bytes
10
+ C_secretkeybytes = C_secretbytes + C_publickeybytes
11
+ C_legacysecretkeybytes = C_legacysecretbytes + C_publickeybytes
12
+ C_signaturebytes = C_bytes + C_bytes
13
+ C_B = JOSE::JWA::Edwards448Point.stdbase.freeze
14
+
15
+ def secret_to_curve448(secret)
16
+ raise ArgumentError, "secret must be #{C_secretbytes} bytes" if secret.bytesize != C_secretbytes and secret.bytesize != C_legacysecretbytes
17
+ curve448_scalar = JOSE::JWA::SHA3.shake256(secret, 114)[0, 56]
18
+ curve448_scalar.setbyte(0, curve448_scalar.getbyte(0) & 252)
19
+ curve448_scalar.setbyte(55, curve448_scalar.getbyte(55) | 128)
20
+ return curve448_scalar
21
+ end
22
+
23
+ def secret_to_pk(secret)
24
+ raise ArgumentError, "secret must be #{C_secretbytes} bytes" if secret.bytesize != C_secretbytes and secret.bytesize != C_legacysecretbytes
25
+ return (C_B * OpenSSL::BN.new(secret_to_curve448(secret).reverse, 2).to_i).encode()
26
+ end
27
+
28
+ def keypair(secret = nil)
29
+ secret ||= SecureRandom.random_bytes(C_secretbytes)
30
+ pk = secret_to_pk(secret)
31
+ sk = secret + pk
32
+ return pk, sk
33
+ end
34
+
35
+ def sk_to_secret(sk)
36
+ return sk[0, C_secretbytes] if sk.bytesize == C_secretkeybytes
37
+ return sk[0, C_legacysecretbytes] if sk.bytesize == C_legacysecretkeybytes
38
+ raise ArgumentError, "sk must be #{C_secretkeybytes} bytes"
39
+ end
40
+
41
+ def sk_to_pk(sk)
42
+ return sk[C_secretbytes, C_secretkeybytes] if sk.bytesize == C_secretkeybytes
43
+ return sk[C_legacysecretbytes, C_legacysecretkeybytes] if sk.bytesize == C_legacysecretkeybytes
44
+ raise ArgumentError, "sk must be #{C_secretkeybytes} bytes"
45
+ end
46
+
47
+ def sk_to_curve448(sk)
48
+ return secret_to_curve448(sk_to_secret(sk))
49
+ end
50
+
51
+ def pk_to_curve448(pk)
52
+ raise ArgumentError, "pk must be #{C_publickeybytes} bytes" if pk.bytesize != C_publickeybytes
53
+ a = C_B.decode(pk)
54
+ u = a.y.sqr / a.x.sqr
55
+ return u.to_bytes(448)
56
+ end
57
+
58
+ def sign(m, sk, ctx = nil)
59
+ raise ArgumentError, "sk must be #{C_secretkeybytes} bytes" if sk.bytesize != C_secretkeybytes and sk.bytesize != C_legacysecretkeybytes
60
+ ctx ||= ''
61
+ raise ArgumentError, "ctx must be 255 bytes or smaller" if ctx.bytesize > 255
62
+ secret, pk = nil, nil
63
+ if sk.bytesize == C_secretkeybytes
64
+ secret, pk = sk[0, 57], sk[57, 114]
65
+ elsif sk.bytesize == C_legacysecretkeybytes
66
+ secret, pk = sk[0, 32], sk[32, 89]
67
+ end
68
+ khash = JOSE::JWA::SHA3.shake256(secret, 114)
69
+ curve448_scalar, seed = khash[0, 57], khash[57, 114]
70
+ curve448_scalar.setbyte(0, curve448_scalar.getbyte(0) & 252)
71
+ curve448_scalar.setbyte(55, curve448_scalar.getbyte(55) | 128)
72
+ curve448_scalar.setbyte(56, 0)
73
+ a_s = OpenSSL::BN.new(curve448_scalar.reverse, 2).to_i
74
+ # Calculate r_s and r (r only used in encoded form)
75
+ r_s = (OpenSSL::BN.new(JOSE::JWA::SHA3.shake256(['SigEd448', 0, ctx.bytesize, ctx, seed, m].pack('A*CCA*A*A*'), 114).reverse, 2) % JOSE::JWA::Edwards448Point::L).to_i
76
+ r = (C_B * r_s).encode()
77
+ # Calculate h.
78
+ h = (OpenSSL::BN.new(JOSE::JWA::SHA3.shake256(['SigEd448', 0, ctx.bytesize, ctx, r, pk, m].pack('A*CCA*A*A*A*'), 114).reverse, 2) % JOSE::JWA::Edwards448Point::L).to_i
79
+ # Calculate s.
80
+ s = OpenSSL::BN.new((r_s+h*a_s) % JOSE::JWA::Edwards448Point::L).to_s(2).rjust(C_bytes, JOSE::JWA::ZERO_PAD).reverse
81
+ # The final signature is concatenation of r and s.
82
+ return r+s
83
+ end
84
+
85
+ def sign_ph(m, sk, ctx = nil)
86
+ raise ArgumentError, "sk must be #{C_secretkeybytes} bytes" if sk.bytesize != C_secretkeybytes and sk.bytesize != C_legacysecretkeybytes
87
+ ctx ||= ''
88
+ raise ArgumentError, "ctx must be 255 bytes or smaller" if ctx.bytesize > 255
89
+ m = JOSE::JWA::SHA3.shake256(['SigEd448', 2, ctx.bytesize, ctx, m].pack('A*CCA*A*'), 64)
90
+ secret, pk = nil, nil
91
+ if sk.bytesize == C_secretkeybytes
92
+ secret, pk = sk[0, 57], sk[57, 114]
93
+ elsif sk.bytesize == C_legacysecretkeybytes
94
+ secret, pk = sk[0, 32], sk[32, 89]
95
+ end
96
+ khash = JOSE::JWA::SHA3.shake256(secret, 114)
97
+ curve448_scalar, seed = khash[0, 57], khash[57, 114]
98
+ curve448_scalar.setbyte(0, curve448_scalar.getbyte(0) & 252)
99
+ curve448_scalar.setbyte(55, curve448_scalar.getbyte(55) | 128)
100
+ curve448_scalar.setbyte(56, 0)
101
+ a_s = OpenSSL::BN.new(curve448_scalar.reverse, 2).to_i
102
+ # Calculate r_s and r (r only used in encoded form)
103
+ r_s = (OpenSSL::BN.new(JOSE::JWA::SHA3.shake256(['SigEd448', 1, ctx.bytesize, ctx, seed, m].pack('A*CCA*A*A*'), 114).reverse, 2) % JOSE::JWA::Edwards448Point::L).to_i
104
+ r = (C_B * r_s).encode()
105
+ # Calculate h.
106
+ h = (OpenSSL::BN.new(JOSE::JWA::SHA3.shake256(['SigEd448', 1, ctx.bytesize, ctx, r, pk, m].pack('A*CCA*A*A*A*'), 114).reverse, 2) % JOSE::JWA::Edwards448Point::L).to_i
107
+ # Calculate s.
108
+ s = OpenSSL::BN.new((r_s+h*a_s) % JOSE::JWA::Edwards448Point::L).to_s(2).rjust(C_bytes, JOSE::JWA::ZERO_PAD).reverse
109
+ # The final signature is concatenation of r and s.
110
+ return r+s
111
+ end
112
+
113
+ def verify(sig, m, pk, ctx = nil)
114
+ ctx ||= ''
115
+ raise ArgumentError, "ctx must be 255 bytes or smaller" if ctx.bytesize > 255
116
+ # Sanity-check sizes.
117
+ return false if sig.bytesize != C_signaturebytes
118
+ return false if pk.bytesize != C_publickeybytes
119
+ # Split signature into R and S, and parse.
120
+ r, s = sig[0, 57], sig[57, 114]
121
+ r_p, s_s = C_B.decode(r), OpenSSL::BN.new(s.reverse, 2).to_i
122
+ # Parse public key.
123
+ a_p = C_B.decode(pk)
124
+ # Check parse results.
125
+ return false if r_p.nil? or a_p.nil? or s_s > JOSE::JWA::Edwards448Point::L
126
+ # Calculate h.
127
+ h = (OpenSSL::BN.new(JOSE::JWA::SHA3.shake256(['SigEd448', 0, ctx.bytesize, ctx, r, pk, m].pack('A*CCA*A*A*A*'), 114).reverse, 2) % JOSE::JWA::Edwards448Point::L).to_i
128
+ # Calculate left and right sides of check eq.
129
+ rhs = r_p + (a_p * h)
130
+ lhs = C_B * s_s
131
+ JOSE::JWA::Edwards448Point::C.times do
132
+ lhs = lhs.double()
133
+ rhs = rhs.double()
134
+ end
135
+ # Check eq. holds?
136
+ return lhs == rhs
137
+ end
138
+
139
+ def verify_ph(sig, m, pk, ctx = nil)
140
+ ctx ||= ''
141
+ raise ArgumentError, "ctx must be 255 bytes or smaller" if ctx.bytesize > 255
142
+ m = JOSE::JWA::SHA3.shake256(['SigEd448', 2, ctx.bytesize, ctx, m].pack('A*CCA*A*'), 64)
143
+ # Sanity-check sizes.
144
+ return false if sig.bytesize != C_signaturebytes
145
+ return false if pk.bytesize != C_publickeybytes
146
+ # Split signature into R and S, and parse.
147
+ r, s = sig[0, 57], sig[57, 114]
148
+ r_p, s_s = C_B.decode(r), OpenSSL::BN.new(s.reverse, 2).to_i
149
+ # Parse public key.
150
+ a_p = C_B.decode(pk)
151
+ # Check parse results.
152
+ return false if r_p.nil? or a_p.nil? or s_s > JOSE::JWA::Edwards448Point::L
153
+ # Calculate h.
154
+ h = (OpenSSL::BN.new(JOSE::JWA::SHA3.shake256(['SigEd448', 1, ctx.bytesize, ctx, r, pk, m].pack('A*CCA*A*A*A*'), 114).reverse, 2) % JOSE::JWA::Edwards448Point::L).to_i
155
+ # Calculate left and right sides of check eq.
156
+ rhs = r_p + (a_p * h)
157
+ lhs = C_B * s_s
158
+ JOSE::JWA::Edwards448Point::C.times do
159
+ lhs = lhs.double()
160
+ rhs = rhs.double()
161
+ end
162
+ # Check eq. holds?
163
+ return lhs == rhs
164
+ end
165
+
166
+ end