-
Notifications
You must be signed in to change notification settings - Fork 12
test: add negative BLS verify and FAV cases #304
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 5 commits
74d8ceb
44407ca
a8550ca
94e805d
5e1eb80
594cfa7
9cafa2d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,45 +7,147 @@ const SecretKey = bls.SecretKey; | |
| /// See https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/phase0/beacon-chain.md#bls-signatures | ||
| const DST: []const u8 = "BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_"; | ||
|
|
||
| pub fn sign(secret_key: SecretKey, msg: []const u8) Signature { | ||
| return secret_key.sign(msg, DST, null); | ||
| pub fn sign(secret_key: SecretKey, message: []const u8) Signature { | ||
| return secret_key.sign(message, DST, null); | ||
| } | ||
|
|
||
| /// Verify a signature against a message and public key. | ||
| /// | ||
| /// If `pk_validate` is `true`, the public key will be infinity and group checked. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: comment arg name not same with function arg name
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @spiral-ladder is |
||
| /// | ||
| /// If `sig_groupcheck` is `true`, the signature will be group checked. | ||
| pub fn verify(msg: []const u8, pk: *const PublicKey, sig: *const Signature, in_pk_validate: ?bool, in_sig_groupcheck: ?bool) bls.BlstError!void { | ||
| pub fn verify(message: []const u8, public_key: *const PublicKey, signature: *const Signature, in_pk_validate: ?bool, in_sig_groupcheck: ?bool) bls.BlstError!void { | ||
| const sig_groupcheck = in_sig_groupcheck orelse false; | ||
| const pk_validate = in_pk_validate orelse false; | ||
| try sig.verify(sig_groupcheck, msg, DST, null, pk, pk_validate); | ||
| try signature.verify(sig_groupcheck, message, DST, null, public_key, pk_validate); | ||
| } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Following the repository style guide:
References
|
||
|
|
||
| pub fn fastAggregateVerify(msg: []const u8, pks: []const PublicKey, sig: *const Signature, in_pk_validate: ?bool, in_sigs_group_check: ?bool) !bool { | ||
| /// The `message` must be at least 32 bytes; only the first 32 are passed to | ||
| /// fast aggregate verification. | ||
| pub fn fastAggregateVerify(message: []const u8, public_keys: []const PublicKey, signature: *const Signature, in_pk_validate: ?bool, in_sigs_group_check: ?bool) !bool { | ||
| std.debug.assert(message.len >= 32); | ||
|
|
||
| var pairing_buf: [bls.Pairing.sizeOf()]u8 align(bls.Pairing.buf_align) = undefined; | ||
|
|
||
| const sigs_groupcheck = in_sigs_group_check orelse false; | ||
| const pks_validate = in_pk_validate orelse false; | ||
| return sig.fastAggregateVerify(sigs_groupcheck, &pairing_buf, msg[0..32], DST, pks, pks_validate) catch return false; | ||
| const public_keys_validate = in_pk_validate orelse false; | ||
| return signature.fastAggregateVerify(sigs_groupcheck, &pairing_buf, message[0..32], DST, public_keys, public_keys_validate) catch return false; | ||
| } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Following the repository style guide:
References
|
||
|
|
||
| // TODO: unit tests | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps adding more positive tests for other functions if dropped this comment |
||
| test "bls - sanity" { | ||
| const ikm: [32]u8 = [_]u8{ | ||
| const input_key_material: [32]u8 = [_]u8{ | ||
| 0x93, 0xad, 0x7e, 0x65, 0xde, 0xad, 0x05, 0x2a, 0x08, 0x3a, | ||
| 0x91, 0x0c, 0x8b, 0x72, 0x85, 0x91, 0x46, 0x4c, 0xca, 0x56, | ||
| 0x60, 0x5b, 0xb0, 0x56, 0xed, 0xfe, 0x2b, 0x60, 0xa6, 0x3c, | ||
| 0x48, 0x99, | ||
| }; | ||
| const secret_key = try SecretKey.keyGen(input_key_material[0..], null); | ||
| const message = [_]u8{1} ** 32; | ||
| const signature = sign(secret_key, &message); | ||
| const public_key = secret_key.toPublicKey(); | ||
| try verify(&message, &public_key, &signature, null, null); | ||
|
|
||
| const public_keys = [_]PublicKey{public_key}; | ||
| const public_keys_slice: []const PublicKey = public_keys[0..1]; | ||
| const fast_aggregate_verified = try fastAggregateVerify(&message, public_keys_slice, &signature, null, null); | ||
| try std.testing.expectEqual(true, fast_aggregate_verified); | ||
| } | ||
|
|
||
| test "bls - sign and verify round trip variable-length message" { | ||
| const input_key_material: [32]u8 = [_]u8{ | ||
| 0x93, 0xad, 0x7e, 0x65, 0xde, 0xad, 0x05, 0x2a, 0x08, 0x3a, | ||
| 0x91, 0x0c, 0x8b, 0x72, 0x85, 0x91, 0x46, 0x4c, 0xca, 0x56, | ||
| 0x60, 0x5b, 0xb0, 0x56, 0xed, 0xfe, 0x2b, 0x60, 0xa6, 0x3c, | ||
| 0x48, 0x99, | ||
| }; | ||
| const secret_key = try SecretKey.keyGen(input_key_material[0..], null); | ||
| const message = "ethereum consensus"; | ||
| const signature = sign(secret_key, message); | ||
| const public_key = secret_key.toPublicKey(); | ||
| try verify(message, &public_key, &signature, null, null); | ||
| } | ||
|
|
||
| test "bls - verify with pubkey and signature subgroup checks" { | ||
| const input_key_material: [32]u8 = [_]u8{ | ||
| 0x93, 0xad, 0x7e, 0x65, 0xde, 0xad, 0x05, 0x2a, 0x08, 0x3a, | ||
| 0x91, 0x0c, 0x8b, 0x72, 0x85, 0x91, 0x46, 0x4c, 0xca, 0x56, | ||
| 0x60, 0x5b, 0xb0, 0x56, 0xed, 0xfe, 0x2b, 0x60, 0xa6, 0x3c, | ||
| 0x48, 0x99, | ||
| }; | ||
| const secret_key = try SecretKey.keyGen(input_key_material[0..], null); | ||
| const message = [_]u8{0xab} ** 32; | ||
| const signature = sign(secret_key, &message); | ||
| const public_key = secret_key.toPublicKey(); | ||
| try verify(&message, &public_key, &signature, true, true); | ||
| } | ||
|
|
||
| test "bls - fastAggregateVerify uses only first 32 bytes of longer buffer" { | ||
| const input_key_material: [32]u8 = [_]u8{ | ||
| 0x93, 0xad, 0x7e, 0x65, 0xde, 0xad, 0x05, 0x2a, 0x08, 0x3a, | ||
| 0x91, 0x0c, 0x8b, 0x72, 0x85, 0x91, 0x46, 0x4c, 0xca, 0x56, | ||
| 0x60, 0x5b, 0xb0, 0x56, 0xed, 0xfe, 0x2b, 0x60, 0xa6, 0x3c, | ||
| 0x48, 0x99, | ||
| }; | ||
| const secret_key = try SecretKey.keyGen(input_key_material[0..], null); | ||
| var message_64: [64]u8 = undefined; | ||
| @memset(message_64[32..], 0xcd); | ||
| @memset(message_64[0..32], 0x42); | ||
| const signature = sign(secret_key, message_64[0..32]); | ||
| const public_key = secret_key.toPublicKey(); | ||
| var public_keys = [_]PublicKey{public_key}; | ||
| const fast_aggregate_verified = try fastAggregateVerify(&message_64, public_keys[0..], &signature, null, null); | ||
| try std.testing.expectEqual(true, fast_aggregate_verified); | ||
| } | ||
|
|
||
| test "bls - verify fails on wrong message" { | ||
| const input_key_material: [32]u8 = [_]u8{ | ||
| 0x93, 0xad, 0x7e, 0x65, 0xde, 0xad, 0x05, 0x2a, 0x08, 0x3a, | ||
| 0x91, 0x0c, 0x8b, 0x72, 0x85, 0x91, 0x46, 0x4c, 0xca, 0x56, | ||
| 0x60, 0x5b, 0xb0, 0x56, 0xed, 0xfe, 0x2b, 0x60, 0xa6, 0x3c, | ||
| 0x48, 0x99, | ||
| }; | ||
| const secret_key = try SecretKey.keyGen(input_key_material[0..], null); | ||
| var message = [_]u8{1} ** 32; | ||
| const signature = sign(secret_key, &message); | ||
| const public_key = secret_key.toPublicKey(); | ||
| message[0] ^= 1; | ||
| try std.testing.expectError(bls.BlstError.VerifyFail, verify(&message, &public_key, &signature, null, null)); | ||
| } | ||
|
|
||
| test "bls - verify fails on wrong public key" { | ||
| const input_key_material_a: [32]u8 = [_]u8{ | ||
| 0x93, 0xad, 0x7e, 0x65, 0xde, 0xad, 0x05, 0x2a, 0x08, 0x3a, | ||
| 0x91, 0x0c, 0x8b, 0x72, 0x85, 0x91, 0x46, 0x4c, 0xca, 0x56, | ||
| 0x60, 0x5b, 0xb0, 0x56, 0xed, 0xfe, 0x2b, 0x60, 0xa6, 0x3c, | ||
| 0x48, 0x99, | ||
| }; | ||
| const sk = try SecretKey.keyGen(ikm[0..], null); | ||
| const msg = [_]u8{1} ** 32; | ||
| const sig = sign(sk, &msg); | ||
| const pk = sk.toPublicKey(); | ||
| try verify(&msg, &pk, &sig, null, null); | ||
| const input_key_material_b: [32]u8 = [_]u8{ | ||
| 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, | ||
| 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, | ||
| 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, | ||
| 0x0f, 0x10, | ||
| }; | ||
| const secret_key_a = try SecretKey.keyGen(input_key_material_a[0..], null); | ||
| const secret_key_b = try SecretKey.keyGen(input_key_material_b[0..], null); | ||
| const message = [_]u8{1} ** 32; | ||
| const signature = sign(secret_key_a, &message); | ||
| const public_key_b = secret_key_b.toPublicKey(); | ||
| try std.testing.expectError(bls.BlstError.VerifyFail, verify(&message, &public_key_b, &signature, null, null)); | ||
| } | ||
|
|
||
| var pks = [_]PublicKey{pk}; | ||
| var pks_slice: []const PublicKey = pks[0..1]; | ||
| const result = try fastAggregateVerify(&msg, pks_slice[0..], &sig, null, null); | ||
| try std.testing.expect(result); | ||
| test "bls - fastAggregateVerify false on wrong message" { | ||
| const input_key_material: [32]u8 = [_]u8{ | ||
| 0x93, 0xad, 0x7e, 0x65, 0xde, 0xad, 0x05, 0x2a, 0x08, 0x3a, | ||
| 0x91, 0x0c, 0x8b, 0x72, 0x85, 0x91, 0x46, 0x4c, 0xca, 0x56, | ||
| 0x60, 0x5b, 0xb0, 0x56, 0xed, 0xfe, 0x2b, 0x60, 0xa6, 0x3c, | ||
| 0x48, 0x99, | ||
| }; | ||
| const secret_key = try SecretKey.keyGen(input_key_material[0..], null); | ||
| var message = [_]u8{1} ** 32; | ||
| const signature = sign(secret_key, &message); | ||
| const public_key = secret_key.toPublicKey(); | ||
| message[31] ^= 0xff; | ||
| var public_keys = [_]PublicKey{public_key}; | ||
| const fast_aggregate_verified = try fastAggregateVerify(&message, public_keys[0..], &signature, null, null); | ||
| try std.testing.expectEqual(false, fast_aggregate_verified); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The repository style guide requires asserting all function arguments and maintaining an average of at least two assertions per function to ensure safety and document invariants (lines 51-55). Consider adding assertions for the
messagelength and theDSTconstant to meet this requirement.References