Skip to content
Open
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 103 additions & 1 deletion src/state_transition/utils/bls.zig
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,18 @@ pub fn verify(msg: []const u8, pk: *const PublicKey, sig: *const Signature, in_p
try sig.verify(sig_groupcheck, msg, DST, null, pk, pk_validate);
}

/// The `msg` must be at least 32 bytes; only the first 32 are passed to
/// fast aggregate verification.
pub fn fastAggregateVerify(msg: []const u8, pks: []const PublicKey, sig: *const Signature, in_pk_validate: ?bool, in_sigs_group_check: ?bool) !bool {
std.debug.assert(msg.len >= 32);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The style guide requires that all function arguments be asserted to ensure the function does not operate blindly on data it has not checked. Furthermore, the assertion density should average at least two assertions per function. Adding an assertion for pks.len helps satisfy these requirements.

    std.debug.assert(msg.len >= 32);
    std.debug.assert(pks.len > 0);
References
  1. Assert all function arguments and return values, pre/postconditions and invariants. The assertion density of the code must average a minimum of two assertions per function. (link)


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;
}

// TODO: unit tests
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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{
0x93, 0xad, 0x7e, 0x65, 0xde, 0xad, 0x05, 0x2a, 0x08, 0x3a,
Expand All @@ -49,3 +52,102 @@ test "bls - sanity" {
const result = try fastAggregateVerify(&msg, pks_slice[0..], &sig, null, null);
try std.testing.expect(result);
}

test "bls - sign and verify round trip variable-length message" {
const ikm: [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 = "ethereum consensus";
const sig = sign(sk, msg);
const pk = sk.toPublicKey();
try verify(msg, &pk, &sig, null, null);
}

test "bls - verify with pubkey and signature subgroup checks" {
const ikm: [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{0xab} ** 32;
const sig = sign(sk, &msg);
const pk = sk.toPublicKey();
try verify(&msg, &pk, &sig, true, true);
}

test "bls - fastAggregateVerify uses only first 32 bytes of longer buffer" {
const ikm: [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);
var msg64: [64]u8 = undefined;
@memset(msg64[32..], 0xcd);
@memset(msg64[0..32], 0x42);
const sig = sign(sk, msg64[0..32]);
const pk = sk.toPublicKey();
var pks = [_]PublicKey{pk};
const ok = try fastAggregateVerify(&msg64, pks[0..], &sig, null, null);
try std.testing.expect(ok);
}

test "bls - verify fails on wrong message" {
const ikm: [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);
var msg = [_]u8{1} ** 32;
const sig = sign(sk, &msg);
const pk = sk.toPublicKey();
msg[0] ^= 1;
try std.testing.expectError(bls.BlstError.VerifyFail, verify(&msg, &pk, &sig, null, null));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The style guide prohibits the use of abbreviations for variable names (except for specific cases like sort indices). Please expand ikm, sk, msg, sig, and pk to their full descriptive names. Additionally, the call to expectError should be wrapped to stay within the 100-column limit.

    const initial_keying_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(initial_keying_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),
    );
References
  1. Do not abbreviate variable names, unless the variable is a primitive integer type used as an argument to a sort function or matrix calculation. (link)

}

test "bls - verify fails on wrong public key" {
const ikm_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 ikm_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 sk_a = try SecretKey.keyGen(ikm_a[0..], null);
const sk_b = try SecretKey.keyGen(ikm_b[0..], null);
const msg = [_]u8{1} ** 32;
const sig = sign(sk_a, &msg);
const pk_b = sk_b.toPublicKey();
try std.testing.expectError(bls.BlstError.VerifyFail, verify(&msg, &pk_b, &sig, null, null));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Expand abbreviations ikm_a, ikm_b, sk_a, sk_b, msg, sig, and pk_b to adhere to the style guide's rule against abbreviations. Qualifiers like 'a' and 'b' should be placed last. Also, ensure the expectError call is properly wrapped.

    const initial_keying_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 initial_keying_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(initial_keying_material_a[0..], null);
    const secret_key_b = try SecretKey.keyGen(initial_keying_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),
    );
References
  1. Do not abbreviate variable names. Qualifiers like 'a' and 'b' should be placed last. (link)

}

test "bls - fastAggregateVerify false on wrong message" {
const ikm: [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);
var msg = [_]u8{1} ** 32;
const sig = sign(sk, &msg);
const pk = sk.toPublicKey();
msg[31] ^= 0xff;
var pks = [_]PublicKey{pk};
const result = try fastAggregateVerify(&msg, pks[0..], &sig, null, null);
try std.testing.expect(!result);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Expand abbreviations ikm, sk, msg, sig, pk, and pks. Additionally, avoid negations in assertions by using expectEqual(false, ...) to state the expected outcome positively.

    const initial_keying_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(initial_keying_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 result = try fastAggregateVerify(&message, &public_keys, &signature, null, null);
    try std.testing.expectEqual(false, result);
References
  1. Do not abbreviate variable names. State invariants positively and avoid negations. (link)

Copy link
Copy Markdown
Contributor

@GrapeBaBa GrapeBaBa Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gorusys nit but this is a good suggestion IMO

}
Loading