Skip to content

Commit 5f9a3d6

Browse files
halfagg: Fix z_0 = 1 as in CZ22
1 parent 1ab7cd8 commit 5f9a3d6

File tree

3 files changed

+22
-16
lines changed

3 files changed

+22
-16
lines changed

hacspec-halfagg/src/halfagg.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,16 @@ pub fn hash_halfagg(input: &Seq<(PublicKey, Message, Bytes32)>) -> Bytes32 {
3131
}
3232

3333
pub fn randomizer(pmr: &Seq<(PublicKey, Message, Bytes32)>, index: usize) -> Scalar {
34-
// TODO: The following line hashes i elements and therefore leads to
35-
// quadratic runtime. Instead, we should cache the intermediate result
36-
// and only hash the new element.
37-
scalar_from_bytes(hash_halfagg(
38-
&Seq::<(PublicKey, Message, Bytes32)>::from_slice(pmr, 0, index + 1),
39-
))
34+
if index == 0 {
35+
Scalar::ONE()
36+
} else {
37+
// TODO: The following line hashes i elements and therefore leads to
38+
// quadratic runtime. Instead, we should cache the intermediate result
39+
// and only hash the new element.
40+
scalar_from_bytes(hash_halfagg(
41+
&Seq::<(PublicKey, Message, Bytes32)>::from_slice(pmr, 0, index + 1),
42+
))
43+
}
4044
}
4145

4246
pub type AggregateResult = Result<AggSig, Error>;

hacspec-halfagg/tests/tests.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -79,13 +79,9 @@ fn test_verify_vectors_process(
7979
fn test_verify_vectors() {
8080
#[rustfmt::skip]
8181
let vectors_raw = vec![
82-
(vec![],
83-
"0000000000000000000000000000000000000000000000000000000000000000"),
84-
(vec![("1b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f", "0202020202020202020202020202020202020202020202020202020202020202"),],
85-
"b070aafcea439a4f6f1bbfc2eb66d29d24b0cab74d6b745c3cfb009cc8fe4aa8108f33907612fb748419ebc4004b3169e16e35d5f12b693b6bbc3d4a6982f2f6"),
86-
(vec![("1b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f", "0202020202020202020202020202020202020202020202020202020202020202"),
87-
("462779ad4aad39514614751a71085f2f10e1c7a593e4e030efb5b8721ce55b0b", "0505050505050505050505050505050505050505050505050505050505050505"),],
88-
"b070aafcea439a4f6f1bbfc2eb66d29d24b0cab74d6b745c3cfb009cc8fe4aa8a3afbdb45a6a34bf7c8c00f1b6d7e7d375b54540f13716c87b62e51e2f4f22ffc211db48479c2f546d52b07955e764eb6a142d577245f40a44f5dee468da4244"),
82+
(vec![], "0000000000000000000000000000000000000000000000000000000000000000"),
83+
(vec![("1b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f", "0202020202020202020202020202020202020202020202020202020202020202"),], "b070aafcea439a4f6f1bbfc2eb66d29d24b0cab74d6b745c3cfb009cc8fe4aa80e066c34819936549ff49b6fd4d41edfc401a367b87ddd59fee38177961c225f"),
84+
(vec![("1b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f", "0202020202020202020202020202020202020202020202020202020202020202"),("462779ad4aad39514614751a71085f2f10e1c7a593e4e030efb5b8721ce55b0b", "0505050505050505050505050505050505050505050505050505050505050505"),], "b070aafcea439a4f6f1bbfc2eb66d29d24b0cab74d6b745c3cfb009cc8fe4aa8a3afbdb45a6a34bf7c8c00f1b6d7e7d375b54540f13716c87b62e51e2f4f22ffbf8913ec53226a34892d60252a7052614ca79ae939986828d81d2311957371ad"),
8985
];
9086
let vectors = test_verify_vectors_process(&vectors_raw);
9187
// Uncomment to generate and print test vectors:

half-aggregation.mediawiki

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ Moreover, they came up with an elegant approach to incremental aggregation that
6161
* Incremental aggregation allows non-interactively aggregating additional BIP 340 signatures into an existing half-aggregate signature.
6262
* A half-aggregate signature of ''u'' BIP 340 input signatures is serialized as the ''(u+1)⋅32''-byte array ''r<sub>1</sub> || ... || r<sub>u</sub> || bytes(s)'' where ''r<sub>i</sub>'' is a 32-byte array from input signature ''i'' and ''s'' is a scalar aggregate (see below for details).
6363
* This document does ''not'' specify the aggregation of multiple aggregate signatures (yet). It is possible, but requires changing the encoding of an aggregate signature. Since it is not possible to undo the aggregation of the s-values, when verifying of such an aggregate signature the randomizers need to be the same as when verifying the individual aggregate signature. Therefore, the aggregate signature needs to encode a tree that reveals how the individual signatures were aggregated and how the resulting aggregate signatures were reaggregated.
64-
* There is a possible optimization where the first randomizer ''z<sub>0</sub>'' is set to the constant ''1'' which speeds up verification because ''z<sub>0</sub>⋅R<sub>0</sub> = R<sub>0</sub>''. This specification does not make use of this optimization yet (TODO).
64+
* The first randomizer ''z<sub>0</sub>'' is fixed to the constant ''1'', which speeds up verification because ''z<sub>0</sub>⋅R<sub>0</sub> = R<sub>0</sub>''. This optimization has been suggested and proven secure by [https://eprint.iacr.org/2022/222.pdf Chen and Zhao].
6565
* The maximum number of signatures that can be aggregated is ''2<sup>16</sup> - 1''. Having a maximum value is supposed to prevent integer overflows. This specific value was a conservative choice and may be raised in the future (TODO).
6666
6767
== Description ==
@@ -147,7 +147,10 @@ Input:
147147
** Let ''(pk<sub>i</sub>, m<sub>i</sub>, sig<sub>i</sub>) = pms_to_agg<sub>i-v</sub>''
148148
** Let ''r<sub>i</sub> = sig<sub>i</sub>[0:32]''
149149
** Let ''s<sub>i</sub> = int(sig<sub>i</sub>[32:64])''
150-
** Let ''z<sub>i</sub> = int(hash<sub>HalfAgg/randomizer</sub>(r<sub>0</sub> || pk<sub>0</sub> || m<sub>0</sub> || ... || r<sub>i</sub> || pk<sub>i</sub> || m<sub>i</sub>)) mod n''
150+
** If ''i = 0'':
151+
*** Let ''z<sub>i</sub> = 1''
152+
** Else:
153+
*** Let ''z<sub>i</sub> = int(hash<sub>HalfAgg/randomizer</sub>(r<sub>0</sub> || pk<sub>0</sub> || m<sub>0</sub> || ... || r<sub>i</sub> || pk<sub>i</sub> || m<sub>i</sub>)) mod n''
151154
* Let ''s = int(aggsig[(v⋅32:(v+1)⋅32]) + z<sub>v</sub>⋅s<sub>v</sub> + ... + z<sub>v+u-1</sub>⋅s<sub>v+u-1</sub> mod n''
152155
* Return ''r<sub>0</sub> || ... || r<sub>v+u-1</sub> || bytes(s)''
153156
@@ -169,7 +172,10 @@ The algorithm ''VerifyAggregate(aggsig, pm_aggd<sub>0..u-1</sub>)'' is defined a
169172
** Let ''r<sub>i</sub> = aggsig[i⋅32:(i+1)⋅32]''
170173
** Let ''R<sub>i</sub> = lift_x(int(r<sub>i</sub>))''; fail if that fails
171174
** Let ''e<sub>i</sub> = int(hash<sub>BIP0340/challenge</sub>(bytes(r<sub>i</sub>) || pk<sub>i</sub> || m<sub>i</sub>)) mod n''
172-
** Let ''z<sub>i</sub> = int(hash<sub>HalfAgg/randomizer</sub>(r<sub>0</sub> || pk<sub>0</sub> || m<sub>0</sub> || ... || r<sub>i</sub> || pk<sub>i</sub> || m<sub>i</sub>)) mod n''
175+
** If ''i = 0'':
176+
*** Let ''z<sub>i</sub> = 1''
177+
** Else:
178+
*** Let ''z<sub>i</sub> = int(hash<sub>HalfAgg/randomizer</sub>(r<sub>0</sub> || pk<sub>0</sub> || m<sub>0</sub> || ... || r<sub>i</sub> || pk<sub>i</sub> || m<sub>i</sub>)) mod n''
173179
* Let ''s = int(aggsig[u⋅32:(u+1)⋅32]); fail if ''s &ge; n''
174180
* Fail if ''s⋅G &ne; z<sub>0</sub>⋅(R<sub>0</sub> + e<sub>0</sub>⋅P<sub>0</sub>) + ... + z<sub>u-1</sub>⋅(R<sub>u-1</sub> + e<sub>u-1</sub>⋅P<sub>u-1</sub>)''
175181
* Return success iff no failure occurred before reaching this point.

0 commit comments

Comments
 (0)