jose 0.1.0 → 0.2.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,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