@@ -1245,6 +1245,227 @@ TEST_CASE("Threshold Signatures") {
12451245 REQUIRE (recPk == pks[0 ]);
12461246 REQUIRE (recSig == sig);
12471247 }
1248+
1249+
1250+ typedef std::vector<uint8_t > RawData;
1251+
1252+ struct RecvShare {
1253+ PrivateKey skShare;
1254+ G1Element pkShare;
1255+ std::vector<G1Element> verifVec;
1256+ };
1257+
1258+ class Participant {
1259+ public:
1260+ // Unique identifier
1261+ RawData id;
1262+ // Free coefficient of S(x)
1263+ PrivateKey sk;
1264+ // Free coefficient of P(x)
1265+ G1Element pk;
1266+ // Free coefficient of SIG(x)
1267+ G2Element sig;
1268+ // Coefficients vectors
1269+ std::vector<PrivateKey> sks;
1270+ std::vector<G1Element> pks;
1271+ // Internal shares (contributions)
1272+ std::map<RawData, PrivateKey> sksShares;
1273+ std::map<RawData, G1Element> pksShares;
1274+
1275+ // Map of received shares from each participant id.
1276+ std::map<RawData, RecvShare> recvShares;
1277+
1278+ // The sk generated from the aggregation of all of the received sks shares (contributions).
1279+ PrivateKey skShare;
1280+
1281+ // Map of received aggrSig from each participant id.
1282+ std::map<RawData, G2Element> recvAggrSigs;
1283+
1284+ bool recvShareAndVerificationVector (RawData fromId, const PrivateKey& share, const std::vector<G1Element>& verifVec) {
1285+ G1Element evalPubShare = bls::Threshold::PublicKeyShare (verifVec, Bytes (id));
1286+ REQUIRE (share.GetG1Element () == evalPubShare);
1287+ recvShares.emplace (std::move (fromId), RecvShare{share, evalPubShare, verifVec});
1288+ return true ;
1289+ }
1290+ void recvAggrSigsFrom (RawData& fromId, const G2Element& sigShare) {
1291+ recvAggrSigs.emplace (fromId, sigShare);
1292+ }
1293+ };
1294+
1295+ auto randPrivKey = [&]() {
1296+ RawData buf = getRandomSeed ();
1297+ return PrivateKey::FromByteVector (buf, true );
1298+ };
1299+
1300+ auto randValue = [&](int mod, std::vector<int >& blockValues) {
1301+ uint8_t val = 0 ;
1302+ do { val = getRandomSeed ()[0 ] % mod; } while (std::find (blockValues.begin (), blockValues.end (), val) != blockValues.end ());
1303+ return val;
1304+ };
1305+
1306+ SECTION (" Aggregated SSSS" ) {
1307+ size_t m = 3 ;
1308+ size_t n = 5 ;
1309+
1310+ // First create the participants and their secrets
1311+ std::vector<Participant> participants;
1312+ for (int i=0 ; i < n ; i++) {
1313+ Participant participant;
1314+ participant.id = getRandomSeed ();
1315+ participant.sk = randPrivKey ();
1316+ participant.pk = participant.sk .GetG1Element ();
1317+
1318+ // Create the vectors' coefficients
1319+ participant.sks .emplace_back (participant.sk );
1320+ participant.pks .emplace_back (participant.pk );
1321+ for (int j = 0 ; j < (m-1 ); j++) {
1322+ auto sk = randPrivKey ();
1323+ participant.sks .emplace_back (sk);
1324+ participant.pks .emplace_back (sk.GetG1Element ());
1325+ }
1326+ participants.emplace_back (participant);
1327+ }
1328+
1329+ // Second, create shares for every other participant
1330+ for (Participant& participant : participants) {
1331+ for (int j=0 ; j < n; j++) {
1332+ RawData id = participants[j].id ;
1333+ participant.sksShares .emplace (id, bls::Threshold::PrivateKeyShare (participant.sks , Bytes (id)));
1334+ participant.pksShares .emplace (id, bls::Threshold::PublicKeyShare (participant.pks , Bytes (id)));
1335+ REQUIRE (participant.sksShares [id].GetG1Element () == participant.pksShares [id]);
1336+ }
1337+ }
1338+
1339+ // Third, send shares and verification vectors
1340+ for (Participant& participant : participants) {
1341+ for (int j=0 ; j < n; j++) {
1342+ auto & recipient = participants[j];
1343+ RawData destId = recipient.id ;
1344+ // S(x) evaluated in participant1.id.
1345+ PrivateKey skShare = participant.sksShares .at (destId);
1346+ // Participant P(x) coefficients.
1347+ std::vector<G1Element> verificationVector = participant.pks ;
1348+ // Now let's verify skShare with the verification vector.
1349+ // evaluating the verification vector with the participant id.
1350+ recipient.recvShareAndVerificationVector (participant.id , skShare, verificationVector);
1351+ }
1352+ }
1353+
1354+ // Fourth, now that everyone has everyone's shares and verification vectors, let's aggregate all of them to create each aggregated sk
1355+ // This is done aggregating every received sk share + the participant S(id) own share.
1356+ // Then verify it against the evaluated Pa(id)
1357+ for (Participant& participant : participants) {
1358+ std::vector<PrivateKey> skSharedPrivKeys;
1359+ std::vector<G1Element> pkShares;
1360+ for (const auto & sharesById : participant.recvShares ) {
1361+ skSharedPrivKeys.emplace_back (sharesById.second .skShare );
1362+ pkShares.emplace_back (sharesById.second .pkShare );
1363+ }
1364+ PrivateKey aggregatedSharedKey = PrivateKey::Aggregate (skSharedPrivKeys);
1365+ // Now let's verify that the public key of Sa(participant2_id) is equal to Pa(participant2_id)
1366+ // For that.. let's aggregate all of the verification vectors evaluated at participant2_id.
1367+ G1Element aggregatedPk;
1368+ for (const auto & pkShare : pkShares) {
1369+ aggregatedPk = !aggregatedPk.IsValid () ? pkShare : aggregatedPk + pkShare;
1370+ }
1371+ REQUIRE (aggregatedSharedKey.GetG1Element () == aggregatedPk);
1372+ participant.skShare = aggregatedSharedKey;
1373+ }
1374+
1375+ // Fifth, now that everyone has its own aggrKey, let's sign a common message with it and check if can everyone can recover the SIGa() free coefficient.
1376+ // Then verify that the recovered G2Element validates with the recovered G1Element (lagrange interpolation results for SIGa() and Pa() respectively)
1377+
1378+ // Let's aggregate all the verification vectors to obtain Pa():
1379+ std::vector<G1Element> finalVerifVector (participants[0 ].pks );
1380+ for (int j = 1 ; j < participants.size (); j++) {
1381+ for (int i = 0 ; i < finalVerifVector.size (); i++) {
1382+ finalVerifVector[i] += participants[j].pks .at (i);
1383+ }
1384+ }
1385+
1386+ // Data to be signed.
1387+ std::vector<uint8_t > msgHash = getRandomSeed ();
1388+ for (auto & participant : participants) {
1389+ // Load SiG(0) value for each participant
1390+ participant.sig = bls::Threshold::Sign (participant.sk , Bytes (msgHash));
1391+ REQUIRE (bls::Threshold::Verify (participant.pk , Bytes (msgHash), {participant.sig }));
1392+ // Craft the participant.skShare sig
1393+ G2Element aggrSig = bls::Threshold::Sign (participant.skShare , Bytes (msgHash));
1394+ // Send it to every other participant which will receive the
1395+ // aggrSig and validate that corresponds to Pa() --> checking Pa(id) == participant.aggrPk
1396+ G1Element aggrPk = bls::Threshold::PublicKeyShare (finalVerifVector, Bytes (participant.id ));
1397+ REQUIRE (aggrPk == participant.skShare .GetG1Element ());
1398+ REQUIRE (bls::Threshold::Verify (aggrPk, Bytes (msgHash), {aggrSig}));
1399+ for (auto & recipient : participants) {
1400+ recipient.recvAggrSigsFrom (participant.id , aggrSig);
1401+ }
1402+ }
1403+
1404+ // Let's aggregate all the SIG(0) values to obtain SIGa(0)
1405+ // This will be checked for equality against the recovered threshold signature
1406+ G2Element finalSIG = participants[0 ].sig ;
1407+ for (int j = 1 ; j < participants.size (); j++) {
1408+ finalSIG += participants[j].sig ;
1409+ }
1410+
1411+ // Now that everyone has everyone's sigs, let's take a participant at random and remove some sigs, then try to recover and validate SIGa(0)
1412+ for (int i=0 ; i < 10 ; i++) {
1413+ std::vector<int > blockedParticipants;
1414+ Participant p = participants[randValue ((int )participants.size (), blockedParticipants)];
1415+ // Block two participants at random
1416+ blockedParticipants.emplace_back (randValue ((int )participants.size (), blockedParticipants));
1417+ blockedParticipants.emplace_back (randValue ((int )participants.size (), blockedParticipants));
1418+ std::vector<RawData> blockedIds;
1419+ for (const auto & pos : blockedParticipants) {
1420+ blockedIds.emplace_back (participants[pos].id );
1421+ }
1422+
1423+ // Gather sigs and ids.
1424+ std::vector<G2Element> aggrSigs;
1425+ std::vector<Bytes> ids;
1426+ for (const auto & recvSigShare : p.recvAggrSigs ) {
1427+ if (std::find (blockedIds.begin (), blockedIds.end (), recvSigShare.first ) != blockedIds.end ()) continue ;
1428+ ids.emplace_back (recvSigShare.first );
1429+ aggrSigs.emplace_back (recvSigShare.second );
1430+ }
1431+
1432+ REQUIRE (aggrSigs.size () == m);
1433+
1434+ G2Element freeCoefficientSigs = bls::Threshold::SignatureRecover (aggrSigs, ids);
1435+ REQUIRE (freeCoefficientSigs == finalSIG);
1436+ // This will validate against Pa(0)!
1437+ G1Element freeCoefficientPks = finalVerifVector[0 ];
1438+ REQUIRE (bls::Threshold::Verify (freeCoefficientPks, Bytes (msgHash), freeCoefficientSigs));
1439+
1440+ // And.. as a final check, let's craft Sa(0)
1441+ std::vector<PrivateKey> aggrKeys;
1442+ std::vector<Bytes> ids3;
1443+ for (const auto & participant : participants) {
1444+ if (std::find (blockedIds.begin (), blockedIds.end (), participant.id ) != blockedIds.end ()) continue ;
1445+ aggrKeys.emplace_back (participant.skShare );
1446+ ids3.emplace_back (participant.id );
1447+ }
1448+ // Now recover the free coefficient of Sa()
1449+ PrivateKey finalKey = bls::Threshold::PrivateKeyRecover (aggrKeys, ids3);
1450+ REQUIRE (finalKey.GetG1Element () == freeCoefficientPks);
1451+ REQUIRE (bls::Threshold::Sign (finalKey, Bytes (msgHash)) == freeCoefficientSigs);
1452+
1453+ // Now let's add one valid sig share and check that can recover the free coefficient correctly.
1454+ Participant extraParticipant = participants[blockedParticipants.back ()];
1455+ auto extraRecvAggrSigs = p.recvAggrSigs [extraParticipant.id ];
1456+ ids.emplace_back (extraParticipant.id );
1457+ aggrSigs.emplace_back (extraRecvAggrSigs);
1458+ G2Element freeCoefficientSigs2 = bls::Threshold::SignatureRecover (aggrSigs, ids);
1459+ REQUIRE (freeCoefficientSigs2.IsValid ());
1460+ REQUIRE (bls::Threshold::Verify (freeCoefficientPks, Bytes (msgHash), freeCoefficientSigs2));
1461+
1462+ // Now let's modify one sig share, aggregate again, and check that verification fails
1463+ aggrSigs[0 ] += G2Element::Generator ();
1464+ G2Element freeCoefficientSigs3 = bls::Threshold::SignatureRecover (aggrSigs, ids);
1465+ REQUIRE (freeCoefficientSigs3.IsValid ());
1466+ REQUIRE (!bls::Threshold::Verify (freeCoefficientPks, Bytes (msgHash), freeCoefficientSigs3));
1467+ }
1468+ }
12481469}
12491470
12501471int main (int argc, char * argv[])
0 commit comments