| ... | @@ -92,10 +92,11 @@ pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type { | ... | @@ -92,10 +92,11 @@ pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type { |
| 92 | const s = try Curve.scalar.Scalar.fromBytes(self.s, .Big); | 92 | const s = try Curve.scalar.Scalar.fromBytes(self.s, .Big); |
| 93 | if (r.isZero() or s.isZero()) return error.IdentityElement; | 93 | if (r.isZero() or s.isZero()) return error.IdentityElement; |
| 94 | | 94 | |
| 95 | var h: [Hash.digest_length]u8 = undefined; | | |
| 96 | Hash.hash(msg, &h, .{}); | | |
| 97 | | | |
| 98 | const ht = Curve.scalar.encoded_length; | 95 | const ht = Curve.scalar.encoded_length; |
| | 96 | const h_len = @max(Hash.digest_length, ht); |
| | 97 | var h: [h_len]u8 = [_]u8{0} ** h_len; |
| | 98 | Hash.hash(msg, h[h_len - Hash.digest_length .. h_len], .{}); |
| | 99 | |
| 99 | const z = reduceToScalar(ht, h[0..ht].*); | 100 | const z = reduceToScalar(ht, h[0..ht].*); |
| 100 | if (z.isZero()) { | 101 | if (z.isZero()) { |
| 101 | return error.SignatureVerificationFailed; | 102 | return error.SignatureVerificationFailed; |
| ... | @@ -228,14 +229,16 @@ pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type { | ... | @@ -228,14 +229,16 @@ pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type { |
| 228 | pub fn sign(key_pair: KeyPair, msg: []const u8, noise: ?[noise_length]u8) (IdentityElementError || NonCanonicalError)!Signature { | 229 | pub fn sign(key_pair: KeyPair, msg: []const u8, noise: ?[noise_length]u8) (IdentityElementError || NonCanonicalError)!Signature { |
| 229 | const secret_key = key_pair.secret_key; | 230 | const secret_key = key_pair.secret_key; |
| 230 | | 231 | |
| 231 | var h: [Hash.digest_length]u8 = undefined; | | |
| 232 | Hash.hash(msg, &h, .{}); | | |
| 233 | | | |
| 234 | const scalar_encoded_length = Curve.scalar.encoded_length; | 232 | const scalar_encoded_length = Curve.scalar.encoded_length; |
| | 233 | const h_len = @max(Hash.digest_length, scalar_encoded_length); |
| | 234 | var h: [h_len]u8 = [_]u8{0} ** h_len; |
| | 235 | var h_slice = h[h_len - Hash.digest_length .. h_len]; |
| | 236 | Hash.hash(msg, h_slice, .{}); |
| | 237 | |
| 235 | std.debug.assert(h.len >= scalar_encoded_length); | 238 | std.debug.assert(h.len >= scalar_encoded_length); |
| 236 | const z = reduceToScalar(scalar_encoded_length, h[0..scalar_encoded_length].*); | 239 | const z = reduceToScalar(scalar_encoded_length, h[0..scalar_encoded_length].*); |
| 237 | | 240 | |
| 238 | const k = deterministicScalar(h, secret_key.bytes, noise); | 241 | const k = deterministicScalar(h_slice.*, secret_key.bytes, noise); |
| 239 | | 242 | |
| 240 | const p = try Curve.basePoint.mul(k.toBytes(.Big), .Big); | 243 | const p = try Curve.basePoint.mul(k.toBytes(.Big), .Big); |
| 241 | const xs = p.affineCoordinates().x.toBytes(.Big); | 244 | const xs = p.affineCoordinates().x.toBytes(.Big); |
| ... | @@ -268,6 +271,7 @@ pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type { | ... | @@ -268,6 +271,7 @@ pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type { |
| 268 | fn deterministicScalar(h: [Hash.digest_length]u8, secret_key: Curve.scalar.CompressedScalar, noise: ?[noise_length]u8) Curve.scalar.Scalar { | 271 | fn deterministicScalar(h: [Hash.digest_length]u8, secret_key: Curve.scalar.CompressedScalar, noise: ?[noise_length]u8) Curve.scalar.Scalar { |
| 269 | var k = [_]u8{0x00} ** h.len; | 272 | var k = [_]u8{0x00} ** h.len; |
| 270 | var m = [_]u8{0x00} ** (h.len + 1 + noise_length + secret_key.len + h.len); | 273 | var m = [_]u8{0x00} ** (h.len + 1 + noise_length + secret_key.len + h.len); |
| | 274 | var t = [_]u8{0x00} ** Curve.scalar.encoded_length; |
| 271 | const m_v = m[0..h.len]; | 275 | const m_v = m[0..h.len]; |
| 272 | const m_i = &m[m_v.len]; | 276 | const m_i = &m[m_v.len]; |
| 273 | const m_z = m[m_v.len + 1 ..][0..noise_length]; | 277 | const m_z = m[m_v.len + 1 ..][0..noise_length]; |
| ... | @@ -286,8 +290,13 @@ pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type { | ... | @@ -286,8 +290,13 @@ pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type { |
| 286 | Hmac.create(&k, &m, &k); | 290 | Hmac.create(&k, &m, &k); |
| 287 | Hmac.create(m_v, m_v, &k); | 291 | Hmac.create(m_v, m_v, &k); |
| 288 | while (true) { | 292 | while (true) { |
| 289 | Hmac.create(m_v, m_v, &k); | 293 | var t_off: usize = 0; |
| 290 | if (Curve.scalar.Scalar.fromBytes(m_v[0..Curve.scalar.encoded_length].*, .Big)) |s| return s else |_| {} | 294 | while (t_off < t.len) : (t_off += m_v.len) { |
| | 295 | const t_end = @min(t_off + m_v.len, t.len); |
| | 296 | Hmac.create(m_v, m_v, &k); |
| | 297 | std.mem.copy(u8, t[t_off..t_end], m_v[0 .. t_end - t_off]); |
| | 298 | } |
| | 299 | if (Curve.scalar.Scalar.fromBytes(t, .Big)) |s| return s else |_| {} |
| 291 | mem.copy(u8, m_v, m_v); | 300 | mem.copy(u8, m_v, m_v); |
| 292 | m_i.* = 0x00; | 301 | m_i.* = 0x00; |
| 293 | Hmac.create(&k, m[0 .. m_v.len + 1], &k); | 302 | Hmac.create(&k, m[0 .. m_v.len + 1], &k); |
| ... | @@ -325,6 +334,55 @@ test "ECDSA - Basic operations over Secp256k1" { | ... | @@ -325,6 +334,55 @@ test "ECDSA - Basic operations over Secp256k1" { |
| 325 | try sig2.verify(msg, kp.public_key); | 334 | try sig2.verify(msg, kp.public_key); |
| 326 | } | 335 | } |
| 327 | | 336 | |
| | 337 | test "ECDSA - Basic operations over EcdsaP384Sha256" { |
| | 338 | const Scheme = Ecdsa(crypto.ecc.P384, crypto.hash.sha2.Sha256); |
| | 339 | const kp = try Scheme.KeyPair.create(null); |
| | 340 | const msg = "test"; |
| | 341 | |
| | 342 | var noise: [Scheme.noise_length]u8 = undefined; |
| | 343 | crypto.random.bytes(&noise); |
| | 344 | const sig = try kp.sign(msg, noise); |
| | 345 | try sig.verify(msg, kp.public_key); |
| | 346 | |
| | 347 | const sig2 = try kp.sign(msg, null); |
| | 348 | try sig2.verify(msg, kp.public_key); |
| | 349 | } |
| | 350 | |
| | 351 | test "ECDSA - Verifying a existing signature with EcdsaP384Sha256" { |
| | 352 | const Scheme = Ecdsa(crypto.ecc.P384, crypto.hash.sha2.Sha256); |
| | 353 | // zig fmt: off |
| | 354 | const sk_bytes = [_]u8{ |
| | 355 | 0x6a, 0x53, 0x9c, 0x83, 0x0f, 0x06, 0x86, 0xd9, 0xef, 0xf1, 0xe7, 0x5c, 0xae, |
| | 356 | 0x93, 0xd9, 0x5b, 0x16, 0x1e, 0x96, 0x7c, 0xb0, 0x86, 0x35, 0xc9, 0xea, 0x20, |
| | 357 | 0xdc, 0x2b, 0x02, 0x37, 0x6d, 0xd2, 0x89, 0x72, 0x0a, 0x37, 0xf6, 0x5d, 0x4f, |
| | 358 | 0x4d, 0xf7, 0x97, 0xcb, 0x8b, 0x03, 0x63, 0xc3, 0x2d |
| | 359 | }; |
| | 360 | const msg = [_]u8{ |
| | 361 | 0x64, 0x61, 0x74, 0x61, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x67, 0x6e, |
| | 362 | 0x69, 0x6e, 0x67, 0x0a |
| | 363 | }; |
| | 364 | const sig_ans_bytes = [_]u8{ |
| | 365 | 0x30, 0x64, 0x02, 0x30, 0x7a, 0x31, 0xd8, 0xe0, 0xf8, 0x40, 0x7d, 0x6a, 0xf3, |
| | 366 | 0x1a, 0x5d, 0x02, 0xe5, 0xcb, 0x24, 0x29, 0x1a, 0xac, 0x15, 0x94, 0xd1, 0x5b, |
| | 367 | 0xcd, 0x75, 0x2f, 0x45, 0x79, 0x98, 0xf7, 0x60, 0x9a, 0xd5, 0xca, 0x80, 0x15, |
| | 368 | 0x87, 0x9b, 0x0c, 0x27, 0xe3, 0x01, 0x8b, 0x73, 0x4e, 0x57, 0xa3, 0xd2, 0x9a, |
| | 369 | 0x02, 0x30, 0x33, 0xe0, 0x04, 0x5e, 0x76, 0x1f, 0xc8, 0xcf, 0xda, 0xbe, 0x64, |
| | 370 | 0x95, 0x0a, 0xd4, 0x85, 0x34, 0x33, 0x08, 0x7a, 0x81, 0xf2, 0xf6, 0xb6, 0x94, |
| | 371 | 0x68, 0xc3, 0x8c, 0x5f, 0x88, 0x92, 0x27, 0x5e, 0x4e, 0x84, 0x96, 0x48, 0x42, |
| | 372 | 0x84, 0x28, 0xac, 0x37, 0x93, 0x07, 0xd3, 0x50, 0x32, 0x71, 0xb0 |
| | 373 | }; |
| | 374 | // zig fmt: on |
| | 375 | |
| | 376 | const sk = try Scheme.SecretKey.fromBytes(sk_bytes); |
| | 377 | const kp = try Scheme.KeyPair.fromSecretKey(sk); |
| | 378 | |
| | 379 | const sig_ans = try Scheme.Signature.fromDer(&sig_ans_bytes); |
| | 380 | try sig_ans.verify(&msg, kp.public_key); |
| | 381 | |
| | 382 | const sig = try kp.sign(&msg, null); |
| | 383 | try sig.verify(&msg, kp.public_key); |
| | 384 | } |
| | 385 | |
| 328 | const TestVector = struct { | 386 | const TestVector = struct { |
| 329 | key: []const u8, | 387 | key: []const u8, |
| 330 | msg: []const u8, | 388 | msg: []const u8, |