feat: wakuv2 store (#2780)

Allows runnning a store node depending on node config settings.
This commit is contained in:
Richard Ramos 2022-08-19 12:34:07 -04:00 committed by GitHub
parent a13aa698da
commit ad326fa290
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1101 changed files with 403907 additions and 98868 deletions

View File

@ -28,6 +28,8 @@
// 1657617291_add_multi_transactions_table.up.sql (412B)
// 1660134042_add_social_links_settings_table.up.sql (334B)
// 1660134060_settings_bio.up.sql (91B)
// 1660134070_add_wakuv2_store.up.sql (269B)
// 1660134072_waku2_store_messages.up.sql (497B)
// doc.go (74B)
package migrations
@ -48,7 +50,7 @@ import (
func bindataRead(data []byte, name string) ([]byte, error) {
gz, err := gzip.NewReader(bytes.NewBuffer(data))
if err != nil {
return nil, fmt.Errorf("read %q: %v", name, err)
return nil, fmt.Errorf("read %q: %w", name, err)
}
var buf bytes.Buffer
@ -56,7 +58,7 @@ func bindataRead(data []byte, name string) ([]byte, error) {
clErr := gz.Close()
if err != nil {
return nil, fmt.Errorf("read %q: %v", name, err)
return nil, fmt.Errorf("read %q: %w", name, err)
}
if clErr != nil {
return nil, err
@ -112,7 +114,7 @@ func _1640111208_dummyUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1640111208_dummy.up.sql", size: 258, mode: os.FileMode(0644), modTime: time.Unix(1650884918, 0)}
info := bindataFileInfo{name: "1640111208_dummy.up.sql", size: 258, mode: os.FileMode(0664), modTime: time.Unix(1659444749, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x3e, 0xf0, 0xae, 0x20, 0x6e, 0x75, 0xd1, 0x36, 0x14, 0xf2, 0x40, 0xe5, 0xd6, 0x7a, 0xc4, 0xa5, 0x72, 0xaa, 0xb5, 0x4d, 0x71, 0x97, 0xb8, 0xe8, 0x95, 0x22, 0x95, 0xa2, 0xac, 0xaf, 0x48, 0x58}}
return a, nil
}
@ -132,7 +134,7 @@ func _1642666031_add_removed_clock_to_bookmarksUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1642666031_add_removed_clock_to_bookmarks.up.sql", size: 117, mode: os.FileMode(0644), modTime: time.Unix(1650884918, 0)}
info := bindataFileInfo{name: "1642666031_add_removed_clock_to_bookmarks.up.sql", size: 117, mode: os.FileMode(0664), modTime: time.Unix(1659444749, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x84, 0x4e, 0x38, 0x99, 0x7a, 0xc, 0x90, 0x13, 0xec, 0xfe, 0x2f, 0x55, 0xff, 0xb7, 0xb6, 0xaa, 0x96, 0xc6, 0x92, 0x79, 0xcc, 0xee, 0x4e, 0x99, 0x53, 0xfe, 0x1c, 0xbb, 0x32, 0x2, 0xa4, 0x27}}
return a, nil
}
@ -152,7 +154,7 @@ func _1643644541_gif_api_key_settingUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1643644541_gif_api_key_setting.up.sql", size: 108, mode: os.FileMode(0644), modTime: time.Unix(1650884918, 0)}
info := bindataFileInfo{name: "1643644541_gif_api_key_setting.up.sql", size: 108, mode: os.FileMode(0664), modTime: time.Unix(1659444749, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x1b, 0x94, 0x28, 0xfb, 0x66, 0xd1, 0x7c, 0xb8, 0x89, 0xe2, 0xb4, 0x71, 0x65, 0x24, 0x57, 0x22, 0x95, 0x38, 0x97, 0x3, 0x9b, 0xc6, 0xa4, 0x41, 0x7b, 0xba, 0xf7, 0xdb, 0x70, 0xf7, 0x20, 0x3a}}
return a, nil
}
@ -172,7 +174,7 @@ func _1644188994_recent_stickersUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1644188994_recent_stickers.up.sql", size: 79, mode: os.FileMode(0644), modTime: time.Unix(1650884918, 0)}
info := bindataFileInfo{name: "1644188994_recent_stickers.up.sql", size: 79, mode: os.FileMode(0664), modTime: time.Unix(1659444749, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x1e, 0xad, 0xaa, 0x30, 0xbf, 0x4, 0x7, 0xf8, 0xc3, 0x3, 0xb8, 0x97, 0x23, 0x2b, 0xbd, 0x1c, 0x60, 0x69, 0xb0, 0x42, 0x5e, 0x6b, 0xd, 0xa7, 0xa3, 0x6b, 0x2e, 0xdc, 0x70, 0x13, 0x72, 0x7}}
return a, nil
}
@ -192,7 +194,7 @@ func _1646659233_add_address_to_dapp_permisssionUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1646659233_add_address_to_dapp_permisssion.up.sql", size: 700, mode: os.FileMode(0644), modTime: time.Unix(1650884918, 0)}
info := bindataFileInfo{name: "1646659233_add_address_to_dapp_permisssion.up.sql", size: 700, mode: os.FileMode(0664), modTime: time.Unix(1659444749, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xed, 0xb0, 0x35, 0xcc, 0x2e, 0x16, 0xe6, 0x15, 0x86, 0x2c, 0x37, 0x80, 0xae, 0xa3, 0xc5, 0x31, 0x78, 0x5, 0x9d, 0xcd, 0x7b, 0xeb, 0x5f, 0xf2, 0xb3, 0x74, 0x72, 0xdf, 0xcf, 0x88, 0xb, 0x40}}
return a, nil
}
@ -212,7 +214,7 @@ func _1646841105_add_emoji_accountUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1646841105_add_emoji_account.up.sql", size: 96, mode: os.FileMode(0644), modTime: time.Unix(1650884918, 0)}
info := bindataFileInfo{name: "1646841105_add_emoji_account.up.sql", size: 96, mode: os.FileMode(0664), modTime: time.Unix(1659444749, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe6, 0x77, 0x29, 0x95, 0x18, 0x64, 0x82, 0x63, 0xe7, 0xaf, 0x6c, 0xa9, 0x15, 0x7d, 0x46, 0xa6, 0xbc, 0xdf, 0xa7, 0xd, 0x2b, 0xd2, 0x2d, 0x97, 0x4d, 0xa, 0x6b, 0xd, 0x6e, 0x90, 0x42, 0x5c}}
return a, nil
}
@ -232,7 +234,7 @@ func _1647278782_display_nameUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1647278782_display_name.up.sql", size: 110, mode: os.FileMode(0644), modTime: time.Unix(1650884918, 0)}
info := bindataFileInfo{name: "1647278782_display_name.up.sql", size: 110, mode: os.FileMode(0664), modTime: time.Unix(1659444749, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf4, 0xa1, 0x1f, 0x3e, 0x61, 0x65, 0x8d, 0xff, 0xee, 0xde, 0xc5, 0x91, 0xd9, 0x5c, 0xb5, 0xe2, 0xf0, 0xb7, 0xe7, 0x5c, 0x5c, 0x16, 0x25, 0x89, 0xee, 0x78, 0x12, 0xea, 0x3e, 0x48, 0x41, 0xa6}}
return a, nil
}
@ -252,7 +254,7 @@ func _1647862838_reset_last_backupUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1647862838_reset_last_backup.up.sql", size: 37, mode: os.FileMode(0644), modTime: time.Unix(1650884918, 0)}
info := bindataFileInfo{name: "1647862838_reset_last_backup.up.sql", size: 37, mode: os.FileMode(0664), modTime: time.Unix(1659444749, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x21, 0xe3, 0xd5, 0xf6, 0x5f, 0xfe, 0x65, 0xfa, 0x1d, 0x88, 0xf8, 0x5f, 0x24, 0x71, 0x34, 0x68, 0x96, 0x2a, 0x60, 0x87, 0x15, 0x82, 0x4d, 0x8a, 0x59, 0x3d, 0x1f, 0xd8, 0x56, 0xd4, 0xfb, 0xda}}
return a, nil
}
@ -272,7 +274,7 @@ func _1647871652_add_settings_sync_clock_tableUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1647871652_add_settings_sync_clock_table.up.sql", size: 1044, mode: os.FileMode(0644), modTime: time.Unix(1650884918, 0)}
info := bindataFileInfo{name: "1647871652_add_settings_sync_clock_table.up.sql", size: 1044, mode: os.FileMode(0664), modTime: time.Unix(1659444749, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd8, 0x58, 0xec, 0x85, 0x90, 0xfa, 0x30, 0x98, 0x98, 0x9a, 0xa6, 0xa8, 0x96, 0x2b, 0x38, 0x93, 0xf3, 0xae, 0x46, 0x74, 0xa4, 0x41, 0x62, 0x9b, 0x2, 0x86, 0xbf, 0xe5, 0x2a, 0xce, 0xe2, 0xc0}}
return a, nil
}
@ -292,7 +294,7 @@ func _1647880168_add_torrent_configUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1647880168_add_torrent_config.up.sql", size: 211, mode: os.FileMode(0644), modTime: time.Unix(1650884918, 0)}
info := bindataFileInfo{name: "1647880168_add_torrent_config.up.sql", size: 211, mode: os.FileMode(0664), modTime: time.Unix(1659444749, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x1, 0x92, 0x22, 0x37, 0x96, 0xf3, 0xb5, 0x5b, 0x27, 0xd0, 0x7d, 0x43, 0x5, 0x4e, 0x9d, 0xe2, 0x49, 0xbe, 0x86, 0x31, 0xa1, 0x89, 0xff, 0xd6, 0x51, 0xe0, 0x9c, 0xb, 0xda, 0xfc, 0xf2, 0x93}}
return a, nil
}
@ -312,7 +314,7 @@ func _1647882837_add_communities_settings_tableUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1647882837_add_communities_settings_table.up.sql", size: 206, mode: os.FileMode(0644), modTime: time.Unix(1650884918, 0)}
info := bindataFileInfo{name: "1647882837_add_communities_settings_table.up.sql", size: 206, mode: os.FileMode(0664), modTime: time.Unix(1659444749, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xbd, 0x87, 0x78, 0x99, 0xd9, 0x5d, 0xbd, 0xf7, 0x57, 0x9c, 0xca, 0x97, 0xbd, 0xb3, 0xe9, 0xb5, 0x89, 0x31, 0x3f, 0xf6, 0x5c, 0x13, 0xb, 0xc3, 0x54, 0x93, 0x18, 0x40, 0x7, 0x82, 0xfe, 0x7e}}
return a, nil
}
@ -332,7 +334,7 @@ func _1647956635_add_waku_messages_tableUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1647956635_add_waku_messages_table.up.sql", size: 266, mode: os.FileMode(0644), modTime: time.Unix(1650884918, 0)}
info := bindataFileInfo{name: "1647956635_add_waku_messages_table.up.sql", size: 266, mode: os.FileMode(0664), modTime: time.Unix(1659444749, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd1, 0xe, 0xe1, 0xdc, 0xda, 0x2e, 0x89, 0x8d, 0xdc, 0x2a, 0x1c, 0x13, 0xa1, 0xfc, 0xfe, 0xf, 0xb2, 0xb9, 0x85, 0xc8, 0x45, 0xd6, 0xd1, 0x7, 0x5c, 0xa3, 0x8, 0x47, 0x44, 0x6d, 0x96, 0xe0}}
return a, nil
}
@ -352,7 +354,7 @@ func _1648554928_network_testUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1648554928_network_test.up.sql", size: 132, mode: os.FileMode(0644), modTime: time.Unix(1650884918, 0)}
info := bindataFileInfo{name: "1648554928_network_test.up.sql", size: 132, mode: os.FileMode(0664), modTime: time.Unix(1659444749, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x9a, 0xc5, 0x7f, 0x87, 0xf3, 0x2c, 0xf7, 0xbb, 0xd3, 0x3a, 0x4e, 0x76, 0x88, 0xca, 0xaf, 0x73, 0xce, 0x8f, 0xa1, 0xf6, 0x3d, 0x4d, 0xed, 0x6f, 0x49, 0xf2, 0xfe, 0x56, 0x2a, 0x60, 0x68, 0xca}}
return a, nil
}
@ -372,7 +374,7 @@ func _1649174829_add_visitble_tokenUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1649174829_add_visitble_token.up.sql", size: 84, mode: os.FileMode(0644), modTime: time.Unix(1651569001, 0)}
info := bindataFileInfo{name: "1649174829_add_visitble_token.up.sql", size: 84, mode: os.FileMode(0664), modTime: time.Unix(1659444749, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xa3, 0x22, 0xc0, 0x2b, 0x3f, 0x4f, 0x3d, 0x5e, 0x4c, 0x68, 0x7c, 0xd0, 0x15, 0x36, 0x9f, 0xec, 0xa1, 0x2a, 0x7b, 0xb4, 0xe3, 0xc6, 0xc9, 0xb4, 0x81, 0x50, 0x4a, 0x11, 0x3b, 0x35, 0x7, 0xcf}}
return a, nil
}
@ -392,7 +394,7 @@ func _1649882262_add_derived_from_accountsUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1649882262_add_derived_from_accounts.up.sql", size: 110, mode: os.FileMode(0644), modTime: time.Unix(1651569001, 0)}
info := bindataFileInfo{name: "1649882262_add_derived_from_accounts.up.sql", size: 110, mode: os.FileMode(0664), modTime: time.Unix(1659444749, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x11, 0xb9, 0x44, 0x4d, 0x85, 0x8d, 0x7f, 0xb4, 0xae, 0x4f, 0x5c, 0x66, 0x64, 0xb6, 0xe2, 0xe, 0x3d, 0xad, 0x9d, 0x8, 0x4f, 0xab, 0x6e, 0xa8, 0x7d, 0x76, 0x3, 0xad, 0x96, 0x1, 0xee, 0x5c}}
return a, nil
}
@ -412,7 +414,7 @@ func _1650612625_add_community_message_archive_hashes_tableUpSql() (*asset, erro
return nil, err
}
info := bindataFileInfo{name: "1650612625_add_community_message_archive_hashes_table.up.sql", size: 130, mode: os.FileMode(0644), modTime: time.Unix(1652180449, 0)}
info := bindataFileInfo{name: "1650612625_add_community_message_archive_hashes_table.up.sql", size: 130, mode: os.FileMode(0664), modTime: time.Unix(1659444749, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x48, 0x31, 0xb3, 0x75, 0x23, 0xe2, 0x45, 0xe, 0x47, 0x1b, 0x35, 0xa5, 0x6e, 0x83, 0x4e, 0x64, 0x7d, 0xd7, 0xa2, 0xda, 0xe9, 0x53, 0xf1, 0x16, 0x86, 0x2c, 0x57, 0xad, 0xfa, 0xca, 0x39, 0xde}}
return a, nil
}
@ -432,7 +434,7 @@ func _1650616788_add_communities_archives_info_tableUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1650616788_add_communities_archives_info_table.up.sql", size: 208, mode: os.FileMode(0644), modTime: time.Unix(1652180449, 0)}
info := bindataFileInfo{name: "1650616788_add_communities_archives_info_table.up.sql", size: 208, mode: os.FileMode(0664), modTime: time.Unix(1659444749, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd1, 0x4f, 0x80, 0x45, 0xb9, 0xd9, 0x15, 0xe2, 0x78, 0xd0, 0xcb, 0x71, 0xc1, 0x1b, 0xb7, 0x1b, 0x1b, 0x97, 0xfe, 0x47, 0x53, 0x3c, 0x62, 0xbc, 0xdd, 0x3a, 0x94, 0x1a, 0xc, 0x48, 0x76, 0xe}}
return a, nil
}
@ -452,7 +454,7 @@ func _1652715604_add_clock_accountsUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1652715604_add_clock_accounts.up.sql", size: 62, mode: os.FileMode(0644), modTime: time.Unix(1653314960, 0)}
info := bindataFileInfo{name: "1652715604_add_clock_accounts.up.sql", size: 62, mode: os.FileMode(0664), modTime: time.Unix(1659444749, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xb6, 0xd9, 0x8d, 0x73, 0xc9, 0xef, 0xfa, 0xb1, 0x4b, 0xa5, 0xf3, 0x5, 0x19, 0x26, 0x46, 0xf8, 0x47, 0x93, 0xdb, 0xac, 0x2, 0xef, 0xf9, 0x71, 0x56, 0x83, 0xe6, 0x2d, 0xb0, 0xd7, 0x83, 0x5c}}
return a, nil
}
@ -472,7 +474,7 @@ func _1653037334_add_notifications_settings_tableUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1653037334_add_notifications_settings_table.up.sql", size: 1276, mode: os.FileMode(0644), modTime: time.Unix(1654616593, 0)}
info := bindataFileInfo{name: "1653037334_add_notifications_settings_table.up.sql", size: 1276, mode: os.FileMode(0664), modTime: time.Unix(1659444749, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x4b, 0xc4, 0x65, 0xac, 0xa, 0xf2, 0xef, 0xb6, 0x39, 0x3c, 0xc5, 0xb1, 0xb2, 0x9c, 0x86, 0x58, 0xe0, 0x38, 0xcb, 0x57, 0x3c, 0x76, 0x73, 0x87, 0x79, 0x4e, 0xf6, 0xed, 0xb0, 0x8e, 0x9e, 0xa}}
return a, nil
}
@ -492,7 +494,7 @@ func _1654702119_add_mutual_contact_settingsUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1654702119_add_mutual_contact_settings.up.sql", size: 78, mode: os.FileMode(0644), modTime: time.Unix(1655124437, 0)}
info := bindataFileInfo{name: "1654702119_add_mutual_contact_settings.up.sql", size: 78, mode: os.FileMode(0664), modTime: time.Unix(1659444749, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x26, 0x66, 0x67, 0x50, 0xfe, 0xd7, 0xe3, 0x29, 0x8b, 0xff, 0x9d, 0x5a, 0x87, 0xa7, 0x99, 0x6e, 0xd6, 0xcd, 0x2e, 0xbb, 0x17, 0xdf, 0x7f, 0xf7, 0xa3, 0xfa, 0x32, 0x7c, 0x2d, 0x92, 0xc8, 0x74}}
return a, nil
}
@ -512,7 +514,7 @@ func _1655375270_add_clock_field_to_communities_settings_tableUpSql() (*asset, e
return nil, err
}
info := bindataFileInfo{name: "1655375270_add_clock_field_to_communities_settings_table.up.sql", size: 74, mode: os.FileMode(0644), modTime: time.Unix(1655479371, 0)}
info := bindataFileInfo{name: "1655375270_add_clock_field_to_communities_settings_table.up.sql", size: 74, mode: os.FileMode(0664), modTime: time.Unix(1659444749, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x19, 0xc5, 0xc0, 0xf9, 0x84, 0x53, 0xdf, 0x83, 0xcf, 0xb6, 0x40, 0x6d, 0xf5, 0xdc, 0x77, 0x37, 0xb7, 0xe3, 0xa, 0x75, 0xe7, 0x6, 0x11, 0xca, 0x2b, 0x51, 0x92, 0xdd, 0x7d, 0xdb, 0xc3, 0xf5}}
return a, nil
}
@ -532,7 +534,7 @@ func _1655385721_drop_networks_configUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1655385721_drop_networks_config.up.sql", size: 27, mode: os.FileMode(0644), modTime: time.Unix(1657891180, 0)}
info := bindataFileInfo{name: "1655385721_drop_networks_config.up.sql", size: 27, mode: os.FileMode(0664), modTime: time.Unix(1659444749, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xfc, 0xa7, 0x20, 0xbb, 0x67, 0x21, 0xe, 0xc6, 0xc8, 0x21, 0x74, 0xe0, 0xce, 0xc8, 0xe2, 0x2, 0xb4, 0xea, 0xf0, 0xe5, 0xc4, 0x4d, 0xdd, 0xd4, 0x52, 0x31, 0xa9, 0x3d, 0xcd, 0xd8, 0x9b, 0xab}}
return a, nil
}
@ -552,7 +554,7 @@ func _1655385724_networks_chaincolor_shortnameUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1655385724_networks_chainColor_shortName.up.sql", size: 220, mode: os.FileMode(0644), modTime: time.Unix(1657891180, 0)}
info := bindataFileInfo{name: "1655385724_networks_chainColor_shortName.up.sql", size: 220, mode: os.FileMode(0664), modTime: time.Unix(1659444749, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd9, 0xe7, 0x84, 0xbb, 0x5f, 0xd2, 0x2c, 0x42, 0x88, 0x62, 0x52, 0xb6, 0x58, 0x31, 0xac, 0xc, 0x96, 0x2b, 0x1b, 0xe5, 0x4e, 0x9a, 0x3a, 0xf6, 0xf6, 0xfc, 0xa9, 0x1a, 0x35, 0x62, 0x28, 0x88}}
return a, nil
}
@ -572,7 +574,7 @@ func _1655456688_add_deleted_at_field_to_bookmarks_tableUpSql() (*asset, error)
return nil, err
}
info := bindataFileInfo{name: "1655456688_add_deleted_at_field_to_bookmarks_table.up.sql", size: 69, mode: os.FileMode(0644), modTime: time.Unix(1657891180, 0)}
info := bindataFileInfo{name: "1655456688_add_deleted_at_field_to_bookmarks_table.up.sql", size: 69, mode: os.FileMode(0664), modTime: time.Unix(1659444749, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe7, 0x9a, 0xbd, 0x9a, 0xc9, 0xf, 0xdf, 0x90, 0x0, 0x5d, 0xea, 0x6e, 0x7d, 0x51, 0x95, 0xcd, 0x90, 0xd3, 0x1a, 0x36, 0x6c, 0xf4, 0xbd, 0xa7, 0x6b, 0xbf, 0xe5, 0xdb, 0xa3, 0x88, 0xe3, 0x50}}
return a, nil
}
@ -592,7 +594,7 @@ func _1655462032_create_bookmarks_deleted_at_indexUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1655462032_create_bookmarks_deleted_at_index.up.sql", size: 81, mode: os.FileMode(0644), modTime: time.Unix(1657891180, 0)}
info := bindataFileInfo{name: "1655462032_create_bookmarks_deleted_at_index.up.sql", size: 81, mode: os.FileMode(0664), modTime: time.Unix(1659444749, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf, 0x8e, 0x20, 0x6b, 0x14, 0x9e, 0xcd, 0x97, 0xd3, 0xfe, 0x62, 0x3, 0x26, 0x59, 0x1, 0x6c, 0x99, 0xef, 0x6d, 0x21, 0xd4, 0xb5, 0xa3, 0xf4, 0x39, 0x40, 0x54, 0x6, 0xd, 0x60, 0x13, 0x38}}
return a, nil
}
@ -612,7 +614,7 @@ func _1657617291_add_multi_transactions_tableUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1657617291_add_multi_transactions_table.up.sql", size: 412, mode: os.FileMode(0644), modTime: time.Unix(1657891180, 0)}
info := bindataFileInfo{name: "1657617291_add_multi_transactions_table.up.sql", size: 412, mode: os.FileMode(0664), modTime: time.Unix(1659444749, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x86, 0xb0, 0x4e, 0x8c, 0x4, 0x82, 0xb4, 0x43, 0xaa, 0xd0, 0x16, 0xdd, 0xcb, 0x88, 0x81, 0xac, 0x4, 0x34, 0x1a, 0x8f, 0x2e, 0xc5, 0x69, 0xb, 0xf0, 0x17, 0xf7, 0xe3, 0x9, 0xe, 0x54, 0xe0}}
return a, nil
}
@ -632,7 +634,7 @@ func _1660134042_add_social_links_settings_tableUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1660134042_add_social_links_settings_table.up.sql", size: 334, mode: os.FileMode(0644), modTime: time.Unix(1660664361, 0)}
info := bindataFileInfo{name: "1660134042_add_social_links_settings_table.up.sql", size: 334, mode: os.FileMode(0664), modTime: time.Unix(1660862195, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x84, 0x73, 0xb6, 0xe7, 0x3f, 0xaa, 0x39, 0x9a, 0x56, 0x56, 0x31, 0xf1, 0x8e, 0x26, 0x23, 0x1, 0xe4, 0xfa, 0x98, 0xfe, 0x78, 0x87, 0x20, 0xcb, 0x52, 0xf4, 0x38, 0x7f, 0xc4, 0x1c, 0x4, 0x22}}
return a, nil
}
@ -652,11 +654,51 @@ func _1660134060_settings_bioUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1660134060_settings_bio.up.sql", size: 91, mode: os.FileMode(0644), modTime: time.Unix(1660664361, 0)}
info := bindataFileInfo{name: "1660134060_settings_bio.up.sql", size: 91, mode: os.FileMode(0664), modTime: time.Unix(1660862195, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x46, 0x25, 0xa0, 0xa6, 0x47, 0xff, 0xbc, 0x2a, 0x0, 0xff, 0x59, 0x4b, 0xb0, 0xc9, 0x4e, 0x15, 0xe4, 0xd9, 0xda, 0xeb, 0xfe, 0x55, 0x98, 0xc3, 0x9d, 0x96, 0xe7, 0xf, 0xd1, 0x5c, 0x93, 0x73}}
return a, nil
}
var __1660134070_add_wakuv2_storeUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\xf4\x09\x71\x0d\x52\x08\x71\x74\xf2\x71\x55\x28\x4f\xcc\x2e\x2d\x33\x8a\x4f\xce\xcf\x4b\xcb\x4c\x57\x70\x74\x71\x51\x70\xf6\xf7\x09\xf5\xf5\x53\x48\xcd\x4b\x4c\xca\x49\x8d\x2f\x2e\xc9\x2f\x4a\x55\x70\xf2\xf7\xf7\x71\x75\xf4\x53\x70\x71\x75\x73\x0c\xf5\x09\x51\x48\x4b\xcc\x29\x4e\xb5\xe6\x22\xca\x20\xb0\x09\xf1\xc9\x89\x05\x89\xc9\x99\x25\x95\x0a\x9e\x7e\x21\x24\x69\x2c\x4e\x4d\xce\xcf\x4b\x29\x86\xe8\xe3\x0a\x0d\x70\x71\x0c\x41\xd7\x13\xec\x1a\x82\xea\x5c\x5b\x05\x03\x1d\x74\x7b\x91\xc4\x60\x46\xda\x2a\x18\x58\x73\x01\x02\x00\x00\xff\xff\xfc\xb0\x43\xcf\x0d\x01\x00\x00")
func _1660134070_add_wakuv2_storeUpSqlBytes() ([]byte, error) {
return bindataRead(
__1660134070_add_wakuv2_storeUpSql,
"1660134070_add_wakuv2_store.up.sql",
)
}
func _1660134070_add_wakuv2_storeUpSql() (*asset, error) {
bytes, err := _1660134070_add_wakuv2_storeUpSqlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "1660134070_add_wakuv2_store.up.sql", size: 269, mode: os.FileMode(0664), modTime: time.Unix(1660925347, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x1d, 0xe6, 0xc3, 0x9, 0xef, 0xdc, 0xae, 0x49, 0x30, 0x78, 0x54, 0xd6, 0xdb, 0xbf, 0xc0, 0x8e, 0x25, 0x8f, 0xfc, 0x67, 0x80, 0x39, 0x37, 0xd4, 0x86, 0xc1, 0x85, 0xc8, 0x99, 0xc4, 0x59, 0xd4}}
return a, nil
}
var __1660134072_waku2_store_messagesUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x8c\x91\xbd\x6a\xc3\x30\x14\x85\x67\xeb\x29\xee\x68\x83\x87\xee\x9e\xe4\x58\x69\x45\x55\xa9\xc8\xd7\x24\x99\x82\x63\x5f\x8a\xa0\x96\x8c\xe5\x84\xf6\xed\x0b\x21\x94\x60\xd3\x9f\xf9\x1c\xbe\x23\x7d\x77\x63\x05\x47\x01\xc8\x4b\x25\x40\x6e\x41\x1b\x04\xb1\x97\x35\xd6\x10\xe7\x30\xd1\x71\xa0\x18\xdb\x37\x8a\x90\xb2\xc4\xf5\x50\x2a\x53\xe6\x2c\x99\xa8\x23\x77\xa1\x09\xdd\x40\x71\x6e\x87\x11\xa4\x46\xf1\x28\xec\x15\xa0\x1b\xa5\x72\x96\x44\xf2\xfd\x1f\x95\x2e\xf8\x99\xfc\x8c\x61\x74\xdd\x95\x7d\x1f\x8e\xe7\x53\x3c\x9f\x7e\xc8\xda\xcf\xf7\xd0\x7e\xbf\xe7\x42\x53\x74\xc1\xaf\x26\xa0\x12\x5b\xde\x28\x84\x87\x9c\x25\x1b\xa3\x6b\xb4\x5c\x6a\x84\xdb\xaf\xa4\xef\xe9\x03\x5e\xad\x7c\xe1\xf6\x00\xcf\xe2\x00\xa9\xeb\x73\xb8\x1b\xce\x58\x06\x3b\x89\x4f\xa6\x41\xb0\x66\x27\xab\x82\xb1\x9b\x33\xa9\x2b\xb1\xff\xcd\xd9\x71\x29\xc0\xe8\x85\xd4\x74\xd1\xc8\x8a\xff\xc3\xd7\x27\x58\xe3\x57\x9d\xac\xf8\x0a\x00\x00\xff\xff\x55\x11\x6d\x5f\xf1\x01\x00\x00")
func _1660134072_waku2_store_messagesUpSqlBytes() ([]byte, error) {
return bindataRead(
__1660134072_waku2_store_messagesUpSql,
"1660134072_waku2_store_messages.up.sql",
)
}
func _1660134072_waku2_store_messagesUpSql() (*asset, error) {
bytes, err := _1660134072_waku2_store_messagesUpSqlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "1660134072_waku2_store_messages.up.sql", size: 497, mode: os.FileMode(0664), modTime: time.Unix(1660925347, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x3e, 0xeb, 0xb4, 0xa0, 0xa1, 0x2b, 0xcb, 0x4c, 0x3c, 0xc6, 0xd0, 0xe8, 0x96, 0xe3, 0x96, 0xf1, 0x4f, 0x1f, 0xe0, 0xe7, 0x1f, 0x85, 0xa3, 0xe, 0xf7, 0x52, 0x56, 0x63, 0x2b, 0xb0, 0x87, 0x7b}}
return a, nil
}
var _docGo = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x2c\xc9\xb1\x0d\xc4\x20\x0c\x05\xd0\x9e\x29\xfe\x02\xd8\xfd\x6d\xe3\x4b\xac\x2f\x44\x82\x09\x78\x7f\xa5\x49\xfd\xa6\x1d\xdd\xe8\xd8\xcf\x55\x8a\x2a\xe3\x47\x1f\xbe\x2c\x1d\x8c\xfa\x6f\xe3\xb4\x34\xd4\xd9\x89\xbb\x71\x59\xb6\x18\x1b\x35\x20\xa2\x9f\x0a\x03\xa2\xe5\x0d\x00\x00\xff\xff\x60\xcd\x06\xbe\x4a\x00\x00\x00")
func docGoBytes() ([]byte, error) {
@ -672,7 +714,7 @@ func docGo() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "doc.go", size: 74, mode: os.FileMode(0644), modTime: time.Unix(1648117578, 0)}
info := bindataFileInfo{name: "doc.go", size: 74, mode: os.FileMode(0664), modTime: time.Unix(1653180231, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xde, 0x7c, 0x28, 0xcd, 0x47, 0xf2, 0xfa, 0x7c, 0x51, 0x2d, 0xd8, 0x38, 0xb, 0xb0, 0x34, 0x9d, 0x4c, 0x62, 0xa, 0x9e, 0x28, 0xc3, 0x31, 0x23, 0xd9, 0xbb, 0x89, 0x9f, 0xa0, 0x89, 0x1f, 0xe8}}
return a, nil
}
@ -768,65 +810,42 @@ func AssetNames() []string {
// _bindata is a table, holding each asset generator, mapped to its name.
var _bindata = map[string]func() (*asset, error){
"1640111208_dummy.up.sql": _1640111208_dummyUpSql,
"1642666031_add_removed_clock_to_bookmarks.up.sql": _1642666031_add_removed_clock_to_bookmarksUpSql,
"1643644541_gif_api_key_setting.up.sql": _1643644541_gif_api_key_settingUpSql,
"1644188994_recent_stickers.up.sql": _1644188994_recent_stickersUpSql,
"1646659233_add_address_to_dapp_permisssion.up.sql": _1646659233_add_address_to_dapp_permisssionUpSql,
"1646841105_add_emoji_account.up.sql": _1646841105_add_emoji_accountUpSql,
"1647278782_display_name.up.sql": _1647278782_display_nameUpSql,
"1647862838_reset_last_backup.up.sql": _1647862838_reset_last_backupUpSql,
"1647871652_add_settings_sync_clock_table.up.sql": _1647871652_add_settings_sync_clock_tableUpSql,
"1647880168_add_torrent_config.up.sql": _1647880168_add_torrent_configUpSql,
"1647882837_add_communities_settings_table.up.sql": _1647882837_add_communities_settings_tableUpSql,
"1647956635_add_waku_messages_table.up.sql": _1647956635_add_waku_messages_tableUpSql,
"1648554928_network_test.up.sql": _1648554928_network_testUpSql,
"1649174829_add_visitble_token.up.sql": _1649174829_add_visitble_tokenUpSql,
"1649882262_add_derived_from_accounts.up.sql": _1649882262_add_derived_from_accountsUpSql,
"1650612625_add_community_message_archive_hashes_table.up.sql": _1650612625_add_community_message_archive_hashes_tableUpSql,
"1650616788_add_communities_archives_info_table.up.sql": _1650616788_add_communities_archives_info_tableUpSql,
"1652715604_add_clock_accounts.up.sql": _1652715604_add_clock_accountsUpSql,
"1653037334_add_notifications_settings_table.up.sql": _1653037334_add_notifications_settings_tableUpSql,
"1654702119_add_mutual_contact_settings.up.sql": _1654702119_add_mutual_contact_settingsUpSql,
"1640111208_dummy.up.sql": _1640111208_dummyUpSql,
"1642666031_add_removed_clock_to_bookmarks.up.sql": _1642666031_add_removed_clock_to_bookmarksUpSql,
"1643644541_gif_api_key_setting.up.sql": _1643644541_gif_api_key_settingUpSql,
"1644188994_recent_stickers.up.sql": _1644188994_recent_stickersUpSql,
"1646659233_add_address_to_dapp_permisssion.up.sql": _1646659233_add_address_to_dapp_permisssionUpSql,
"1646841105_add_emoji_account.up.sql": _1646841105_add_emoji_accountUpSql,
"1647278782_display_name.up.sql": _1647278782_display_nameUpSql,
"1647862838_reset_last_backup.up.sql": _1647862838_reset_last_backupUpSql,
"1647871652_add_settings_sync_clock_table.up.sql": _1647871652_add_settings_sync_clock_tableUpSql,
"1647880168_add_torrent_config.up.sql": _1647880168_add_torrent_configUpSql,
"1647882837_add_communities_settings_table.up.sql": _1647882837_add_communities_settings_tableUpSql,
"1647956635_add_waku_messages_table.up.sql": _1647956635_add_waku_messages_tableUpSql,
"1648554928_network_test.up.sql": _1648554928_network_testUpSql,
"1649174829_add_visitble_token.up.sql": _1649174829_add_visitble_tokenUpSql,
"1649882262_add_derived_from_accounts.up.sql": _1649882262_add_derived_from_accountsUpSql,
"1650612625_add_community_message_archive_hashes_table.up.sql": _1650612625_add_community_message_archive_hashes_tableUpSql,
"1650616788_add_communities_archives_info_table.up.sql": _1650616788_add_communities_archives_info_tableUpSql,
"1652715604_add_clock_accounts.up.sql": _1652715604_add_clock_accountsUpSql,
"1653037334_add_notifications_settings_table.up.sql": _1653037334_add_notifications_settings_tableUpSql,
"1654702119_add_mutual_contact_settings.up.sql": _1654702119_add_mutual_contact_settingsUpSql,
"1655375270_add_clock_field_to_communities_settings_table.up.sql": _1655375270_add_clock_field_to_communities_settings_tableUpSql,
"1655385721_drop_networks_config.up.sql": _1655385721_drop_networks_configUpSql,
"1655385724_networks_chainColor_shortName.up.sql": _1655385724_networks_chaincolor_shortnameUpSql,
"1655456688_add_deleted_at_field_to_bookmarks_table.up.sql": _1655456688_add_deleted_at_field_to_bookmarks_tableUpSql,
"1655462032_create_bookmarks_deleted_at_index.up.sql": _1655462032_create_bookmarks_deleted_at_indexUpSql,
"1657617291_add_multi_transactions_table.up.sql": _1657617291_add_multi_transactions_tableUpSql,
"1660134042_add_social_links_settings_table.up.sql": _1660134042_add_social_links_settings_tableUpSql,
"1660134060_settings_bio.up.sql": _1660134060_settings_bioUpSql,
"doc.go": docGo,
"1655385721_drop_networks_config.up.sql": _1655385721_drop_networks_configUpSql,
"1655385724_networks_chainColor_shortName.up.sql": _1655385724_networks_chaincolor_shortnameUpSql,
"1655456688_add_deleted_at_field_to_bookmarks_table.up.sql": _1655456688_add_deleted_at_field_to_bookmarks_tableUpSql,
"1655462032_create_bookmarks_deleted_at_index.up.sql": _1655462032_create_bookmarks_deleted_at_indexUpSql,
"1657617291_add_multi_transactions_table.up.sql": _1657617291_add_multi_transactions_tableUpSql,
"1660134042_add_social_links_settings_table.up.sql": _1660134042_add_social_links_settings_tableUpSql,
"1660134060_settings_bio.up.sql": _1660134060_settings_bioUpSql,
"1660134070_add_wakuv2_store.up.sql": _1660134070_add_wakuv2_storeUpSql,
"1660134072_waku2_store_messages.up.sql": _1660134072_waku2_store_messagesUpSql,
"doc.go": docGo,
}
// AssetDebug is true if the assets were built with the debug flag enabled.
const AssetDebug = false
// AssetDir returns the file names below a certain
// directory embedded in the file by go-bindata.
// For example if you run go-bindata on data/... and data contains the
@ -868,35 +887,37 @@ type bintree struct {
}
var _bintree = &bintree{nil, map[string]*bintree{
"1640111208_dummy.up.sql": &bintree{_1640111208_dummyUpSql, map[string]*bintree{}},
"1642666031_add_removed_clock_to_bookmarks.up.sql": &bintree{_1642666031_add_removed_clock_to_bookmarksUpSql, map[string]*bintree{}},
"1643644541_gif_api_key_setting.up.sql": &bintree{_1643644541_gif_api_key_settingUpSql, map[string]*bintree{}},
"1644188994_recent_stickers.up.sql": &bintree{_1644188994_recent_stickersUpSql, map[string]*bintree{}},
"1646659233_add_address_to_dapp_permisssion.up.sql": &bintree{_1646659233_add_address_to_dapp_permisssionUpSql, map[string]*bintree{}},
"1646841105_add_emoji_account.up.sql": &bintree{_1646841105_add_emoji_accountUpSql, map[string]*bintree{}},
"1647278782_display_name.up.sql": &bintree{_1647278782_display_nameUpSql, map[string]*bintree{}},
"1647862838_reset_last_backup.up.sql": &bintree{_1647862838_reset_last_backupUpSql, map[string]*bintree{}},
"1647871652_add_settings_sync_clock_table.up.sql": &bintree{_1647871652_add_settings_sync_clock_tableUpSql, map[string]*bintree{}},
"1647880168_add_torrent_config.up.sql": &bintree{_1647880168_add_torrent_configUpSql, map[string]*bintree{}},
"1647882837_add_communities_settings_table.up.sql": &bintree{_1647882837_add_communities_settings_tableUpSql, map[string]*bintree{}},
"1647956635_add_waku_messages_table.up.sql": &bintree{_1647956635_add_waku_messages_tableUpSql, map[string]*bintree{}},
"1648554928_network_test.up.sql": &bintree{_1648554928_network_testUpSql, map[string]*bintree{}},
"1649174829_add_visitble_token.up.sql": &bintree{_1649174829_add_visitble_tokenUpSql, map[string]*bintree{}},
"1649882262_add_derived_from_accounts.up.sql": &bintree{_1649882262_add_derived_from_accountsUpSql, map[string]*bintree{}},
"1650612625_add_community_message_archive_hashes_table.up.sql": &bintree{_1650612625_add_community_message_archive_hashes_tableUpSql, map[string]*bintree{}},
"1650616788_add_communities_archives_info_table.up.sql": &bintree{_1650616788_add_communities_archives_info_tableUpSql, map[string]*bintree{}},
"1652715604_add_clock_accounts.up.sql": &bintree{_1652715604_add_clock_accountsUpSql, map[string]*bintree{}},
"1653037334_add_notifications_settings_table.up.sql": &bintree{_1653037334_add_notifications_settings_tableUpSql, map[string]*bintree{}},
"1654702119_add_mutual_contact_settings.up.sql": &bintree{_1654702119_add_mutual_contact_settingsUpSql, map[string]*bintree{}},
"1655375270_add_clock_field_to_communities_settings_table.up.sql": &bintree{_1655375270_add_clock_field_to_communities_settings_tableUpSql, map[string]*bintree{}},
"1655385721_drop_networks_config.up.sql": &bintree{_1655385721_drop_networks_configUpSql, map[string]*bintree{}},
"1655385724_networks_chainColor_shortName.up.sql": &bintree{_1655385724_networks_chaincolor_shortnameUpSql, map[string]*bintree{}},
"1655456688_add_deleted_at_field_to_bookmarks_table.up.sql": &bintree{_1655456688_add_deleted_at_field_to_bookmarks_tableUpSql, map[string]*bintree{}},
"1655462032_create_bookmarks_deleted_at_index.up.sql": &bintree{_1655462032_create_bookmarks_deleted_at_indexUpSql, map[string]*bintree{}},
"1657617291_add_multi_transactions_table.up.sql": &bintree{_1657617291_add_multi_transactions_tableUpSql, map[string]*bintree{}},
"1660134042_add_social_links_settings_table.up.sql": &bintree{_1660134042_add_social_links_settings_tableUpSql, map[string]*bintree{}},
"1660134060_settings_bio.up.sql": &bintree{_1660134060_settings_bioUpSql, map[string]*bintree{}},
"doc.go": &bintree{docGo, map[string]*bintree{}},
"1640111208_dummy.up.sql": {_1640111208_dummyUpSql, map[string]*bintree{}},
"1642666031_add_removed_clock_to_bookmarks.up.sql": {_1642666031_add_removed_clock_to_bookmarksUpSql, map[string]*bintree{}},
"1643644541_gif_api_key_setting.up.sql": {_1643644541_gif_api_key_settingUpSql, map[string]*bintree{}},
"1644188994_recent_stickers.up.sql": {_1644188994_recent_stickersUpSql, map[string]*bintree{}},
"1646659233_add_address_to_dapp_permisssion.up.sql": {_1646659233_add_address_to_dapp_permisssionUpSql, map[string]*bintree{}},
"1646841105_add_emoji_account.up.sql": {_1646841105_add_emoji_accountUpSql, map[string]*bintree{}},
"1647278782_display_name.up.sql": {_1647278782_display_nameUpSql, map[string]*bintree{}},
"1647862838_reset_last_backup.up.sql": {_1647862838_reset_last_backupUpSql, map[string]*bintree{}},
"1647871652_add_settings_sync_clock_table.up.sql": {_1647871652_add_settings_sync_clock_tableUpSql, map[string]*bintree{}},
"1647880168_add_torrent_config.up.sql": {_1647880168_add_torrent_configUpSql, map[string]*bintree{}},
"1647882837_add_communities_settings_table.up.sql": {_1647882837_add_communities_settings_tableUpSql, map[string]*bintree{}},
"1647956635_add_waku_messages_table.up.sql": {_1647956635_add_waku_messages_tableUpSql, map[string]*bintree{}},
"1648554928_network_test.up.sql": {_1648554928_network_testUpSql, map[string]*bintree{}},
"1649174829_add_visitble_token.up.sql": {_1649174829_add_visitble_tokenUpSql, map[string]*bintree{}},
"1649882262_add_derived_from_accounts.up.sql": {_1649882262_add_derived_from_accountsUpSql, map[string]*bintree{}},
"1650612625_add_community_message_archive_hashes_table.up.sql": {_1650612625_add_community_message_archive_hashes_tableUpSql, map[string]*bintree{}},
"1650616788_add_communities_archives_info_table.up.sql": {_1650616788_add_communities_archives_info_tableUpSql, map[string]*bintree{}},
"1652715604_add_clock_accounts.up.sql": {_1652715604_add_clock_accountsUpSql, map[string]*bintree{}},
"1653037334_add_notifications_settings_table.up.sql": {_1653037334_add_notifications_settings_tableUpSql, map[string]*bintree{}},
"1654702119_add_mutual_contact_settings.up.sql": {_1654702119_add_mutual_contact_settingsUpSql, map[string]*bintree{}},
"1655375270_add_clock_field_to_communities_settings_table.up.sql": {_1655375270_add_clock_field_to_communities_settings_tableUpSql, map[string]*bintree{}},
"1655385721_drop_networks_config.up.sql": {_1655385721_drop_networks_configUpSql, map[string]*bintree{}},
"1655385724_networks_chainColor_shortName.up.sql": {_1655385724_networks_chaincolor_shortnameUpSql, map[string]*bintree{}},
"1655456688_add_deleted_at_field_to_bookmarks_table.up.sql": {_1655456688_add_deleted_at_field_to_bookmarks_tableUpSql, map[string]*bintree{}},
"1655462032_create_bookmarks_deleted_at_index.up.sql": {_1655462032_create_bookmarks_deleted_at_indexUpSql, map[string]*bintree{}},
"1657617291_add_multi_transactions_table.up.sql": {_1657617291_add_multi_transactions_tableUpSql, map[string]*bintree{}},
"1660134042_add_social_links_settings_table.up.sql": {_1660134042_add_social_links_settings_tableUpSql, map[string]*bintree{}},
"1660134060_settings_bio.up.sql": {_1660134060_settings_bioUpSql, map[string]*bintree{}},
"1660134070_add_wakuv2_store.up.sql": {_1660134070_add_wakuv2_storeUpSql, map[string]*bintree{}},
"1660134072_waku2_store_messages.up.sql": {_1660134072_waku2_store_messagesUpSql, map[string]*bintree{}},
"doc.go": {docGo, map[string]*bintree{}},
}}
// RestoreAsset restores an asset under the given directory.

View File

@ -0,0 +1,5 @@
ALTER TABLE wakuv2_config ADD COLUMN enable_store BOOLEAN DEFAULT false;
ALTER TABLE wakuv2_config ADD COLUMN store_capacity INT;
ALTER TABLE wakuv2_config ADD COLUMN store_seconds INT;
UPDATE wakuv2_config SET enable_store = 0, store_capacity = 0, store_seconds = 0;

View File

@ -0,0 +1,13 @@
CREATE TABLE IF NOT EXISTS store_messages (
id BLOB,
receiverTimestamp INTEGER NOT NULL,
senderTimestamp INTEGER NOT NULL,
contentTopic BLOB NOT NULL,
pubsubTopic BLOB NOT NULL,
payload BLOB,
version INTEGER NOT NULL DEFAULT 0,
CONSTRAINT messageIndex PRIMARY KEY (id, pubsubTopic)
) WITHOUT ROWID;
CREATE INDEX IF NOT EXISTS store_message_senderTimestamp ON store_messages(senderTimestamp);
CREATE INDEX IF NOT EXISTS store_message_receiverTimestamp ON store_messages(receiverTimestamp);

177
go.mod
View File

@ -2,7 +2,7 @@ module github.com/status-im/status-go
go 1.18
replace github.com/ethereum/go-ethereum v1.10.16 => github.com/status-im/go-ethereum v1.10.4-status.4
replace github.com/ethereum/go-ethereum v1.10.21 => github.com/status-im/go-ethereum v1.10.4-status.4
replace github.com/docker/docker => github.com/docker/engine v1.4.2-0.20190717161051-705d9623b7c1
@ -10,7 +10,9 @@ replace github.com/nfnt/resize => github.com/status-im/resize v0.0.0-20201215164
replace github.com/forPelevin/gomoji => github.com/status-im/gomoji v1.1.3-0.20220213022530-e5ac4a8732d4
replace github.com/raulk/go-watchdog v1.2.0 => github.com/status-im/go-watchdog v1.2.0-ios-nolibproc
replace github.com/raulk/go-watchdog v1.3.0 => github.com/status-im/go-watchdog v1.2.0-ios-nolibproc
replace github.com/flynn/noise v1.0.0 => github.com/status-im/noise v1.0.1-handshakeMessages
require (
github.com/anacrolix/torrent v1.41.0
@ -19,29 +21,29 @@ require (
github.com/cenkalti/backoff/v3 v3.2.2
github.com/davecgh/go-spew v1.1.1
github.com/deckarep/golang-set v1.8.0
github.com/ethereum/go-ethereum v1.10.16
github.com/ethereum/go-ethereum v1.10.21
github.com/forPelevin/gomoji v1.1.2
github.com/golang/mock v1.6.0
github.com/golang/protobuf v1.5.2
github.com/google/uuid v1.3.0
github.com/hashicorp/go-version v1.2.0
github.com/imdario/mergo v0.3.12
github.com/ipfs/go-cid v0.0.7
github.com/ipfs/go-cid v0.2.0
github.com/ipfs/go-ds-sql v0.3.0
github.com/ipfs/go-log v1.0.5
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a
github.com/keighl/metabolize v0.0.0-20150915210303-97ab655d4034
github.com/kilic/bls12-381 v0.0.0-20200607163746-32e1441c8a9f
github.com/lib/pq v1.9.0
github.com/libp2p/go-libp2p v0.18.0
github.com/libp2p/go-libp2p-core v0.14.0
github.com/libp2p/go-libp2p-peerstore v0.6.0
github.com/libp2p/go-libp2p-pubsub v0.6.1
github.com/lib/pq v1.10.0
github.com/libp2p/go-libp2p v0.21.0
github.com/libp2p/go-libp2p-core v0.19.1
github.com/libp2p/go-libp2p-peerstore v0.7.1
github.com/libp2p/go-libp2p-pubsub v0.7.1-0.20220701163738-60cf38003244
github.com/lucasb-eyer/go-colorful v1.0.3
github.com/mat/besticon v0.0.0-20210314201728-1579f269edb7
github.com/multiformats/go-multiaddr v0.5.0
github.com/multiformats/go-multibase v0.0.3
github.com/multiformats/go-multihash v0.0.15
github.com/multiformats/go-multiaddr v0.6.0
github.com/multiformats/go-multibase v0.1.1
github.com/multiformats/go-multihash v0.2.0
github.com/multiformats/go-varint v0.0.6
github.com/mutecomm/go-sqlcipher v0.0.0-20190227152316-55dbde17881f
github.com/nfnt/resize v0.0.0-00010101000000-000000000000
@ -49,30 +51,28 @@ require (
github.com/oliamb/cutter v0.2.2
github.com/pborman/uuid v1.2.0
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.11.1
github.com/prometheus/client_golang v1.12.1
github.com/russolsen/transit v0.0.0-20180705123435-0794b4c4505a
github.com/status-im/doubleratchet v3.0.0+incompatible
github.com/status-im/go-waku v0.0.0-20220403002242-f1a40fad73c3
github.com/status-im/go-waku-rendezvous v0.0.0-20211018070416-a93f3b70c432
github.com/status-im/go-waku v0.1.1-0.20220819160153-b0761ad70648
github.com/status-im/go-waku-rendezvous v0.0.0-20220817210730-9b9b02b1e880
github.com/status-im/markdown v0.0.0-20220622180305-7ee4aa8bbc3f
github.com/status-im/migrate/v4 v4.6.2-status.2
github.com/status-im/rendezvous v1.3.5-0.20220406135049-e84f589e197a
github.com/status-im/rendezvous v1.3.5
github.com/status-im/status-go/extkeys v1.1.2
github.com/status-im/tcp-shaker v0.0.0-20191114194237-215893130501
github.com/status-im/zxcvbn-go v0.0.0-20220311183720-5e8676676857
github.com/stretchr/testify v1.7.1
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7
github.com/stretchr/testify v1.8.0
github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a
github.com/tsenart/tb v0.0.0-20181025101425-0d2499c8b6e9
github.com/vacp2p/mvds v0.0.24-0.20201124060106-26d8e94130d8
github.com/wealdtech/go-ens/v3 v3.5.0
github.com/wealdtech/go-multicodec v1.4.0
github.com/xeipuuv/gojsonschema v1.2.0
github.com/zenthangplus/goccm v0.0.0-20211005163543-2f2e522aca15
go.uber.org/zap v1.21.0
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838
go.uber.org/zap v1.22.0
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e
golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
gopkg.in/go-playground/validator.v9 v9.31.0
gopkg.in/natefinch/lumberjack.v2 v2.0.0
olympos.io/encoding/edn v0.0.0-20201019073823-d3554ca0b0a3
@ -99,113 +99,100 @@ require (
github.com/anacrolix/upnp v0.1.3-0.20220123035249-922794e51c96 // indirect
github.com/anacrolix/utp v0.1.0 // indirect
github.com/andybalholm/cascadia v1.2.0 // indirect
github.com/benbjohnson/clock v1.1.0 // indirect
github.com/benbjohnson/clock v1.3.0 // indirect
github.com/benbjohnson/immutable v0.3.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bits-and-blooms/bitset v1.2.0 // indirect
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 // indirect
github.com/btcsuite/btcd v0.22.0-beta // indirect
github.com/cespare/xxhash/v2 v2.1.1 // indirect
github.com/btcsuite/btcd v0.22.1 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/cheekybits/genny v1.0.0 // indirect
github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327 // indirect
github.com/coreos/go-systemd/v22 v22.1.0 // indirect
github.com/containerd/cgroups v1.0.4 // indirect
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
github.com/cruxic/go-hmac-drbg v0.0.0-20170206035330-84c46983886d // indirect
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
github.com/docker/go-units v0.4.0 // indirect
github.com/dustin/go-humanize v1.0.0 // indirect
github.com/edsrzf/mmap-go v1.0.0 // indirect
github.com/elastic/gosigar v0.14.1 // indirect
github.com/elastic/gosigar v0.14.2 // indirect
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 // indirect
github.com/flynn/noise v1.0.0 // indirect
github.com/francoispqt/gojay v1.2.13 // indirect
github.com/fsnotify/fsnotify v1.5.1 // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect
github.com/go-ole/go-ole v1.2.5 // indirect
github.com/go-playground/locales v0.13.0 // indirect
github.com/go-playground/universal-translator v0.17.0 // indirect
github.com/go-playground/locales v0.14.0 // indirect
github.com/go-playground/universal-translator v0.18.0 // indirect
github.com/go-stack/stack v1.8.0 // indirect
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
github.com/godbus/dbus/v5 v5.0.3 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-migrate/migrate/v4 v4.8.0 // indirect
github.com/golang-migrate/migrate/v4 v4.15.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/btree v1.0.1 // indirect
github.com/google/gopacket v1.1.19 // indirect
github.com/gorilla/websocket v1.4.2 // indirect
github.com/hashicorp/errwrap v1.0.0 // indirect
github.com/hashicorp/go-multierror v1.0.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect
github.com/holiman/bloomfilter/v2 v2.0.3 // indirect
github.com/holiman/uint256 v1.2.0 // indirect
github.com/huandu/xstrings v1.3.2 // indirect
github.com/huin/goupnp v1.0.2 // indirect
github.com/huin/goupnp v1.0.3 // indirect
github.com/ipfs/go-datastore v0.5.1 // indirect
github.com/ipfs/go-ipfs-util v0.0.2 // indirect
github.com/ipfs/go-log/v2 v2.5.0 // indirect
github.com/ipfs/go-log/v2 v2.5.1 // indirect
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect
github.com/jbenet/goprocess v0.1.4 // indirect
github.com/karalabe/usb v0.0.0-20211005121534-4c5740d64559 // indirect
github.com/klauspost/compress v1.13.6 // indirect
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
github.com/koron/go-ssdp v0.0.2 // indirect
github.com/leodido/go-urn v1.2.0 // indirect
github.com/libp2p/go-buffer-pool v0.0.2 // indirect
github.com/karalabe/usb v0.0.2 // indirect
github.com/klauspost/compress v1.15.1 // indirect
github.com/klauspost/cpuid/v2 v2.0.14 // indirect
github.com/koron/go-ssdp v0.0.3 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
github.com/libp2p/go-cidranger v1.1.0 // indirect
github.com/libp2p/go-conn-security-multistream v0.3.0 // indirect
github.com/libp2p/go-eventbus v0.2.1 // indirect
github.com/libp2p/go-flow-metrics v0.0.3 // indirect
github.com/libp2p/go-libp2p-asn-util v0.1.0 // indirect
github.com/libp2p/go-libp2p-blankhost v0.3.0 // indirect
github.com/libp2p/go-libp2p-connmgr v0.3.1 // indirect
github.com/libp2p/go-libp2p-discovery v0.6.0 // indirect
github.com/libp2p/go-libp2p-mplex v0.6.0 // indirect
github.com/libp2p/go-libp2p-nat v0.1.0 // indirect
github.com/libp2p/go-libp2p-noise v0.3.0 // indirect
github.com/libp2p/go-libp2p-pnet v0.2.0 // indirect
github.com/libp2p/go-libp2p-quic-transport v0.16.1 // indirect
github.com/libp2p/go-libp2p-resource-manager v0.1.5 // indirect
github.com/libp2p/go-libp2p-swarm v0.10.2 // indirect
github.com/libp2p/go-libp2p-tls v0.3.1 // indirect
github.com/libp2p/go-libp2p-transport-upgrader v0.7.1 // indirect
github.com/libp2p/go-libp2p-yamux v0.8.2 // indirect
github.com/libp2p/go-mplex v0.6.0 // indirect
github.com/libp2p/go-msgio v0.1.0 // indirect
github.com/libp2p/go-libp2p-asn-util v0.2.0 // indirect
github.com/libp2p/go-libp2p-resource-manager v0.5.1 // indirect
github.com/libp2p/go-mplex v0.7.0 // indirect
github.com/libp2p/go-msgio v0.2.0 // indirect
github.com/libp2p/go-nat v0.1.0 // indirect
github.com/libp2p/go-netroute v0.2.0 // indirect
github.com/libp2p/go-openssl v0.0.7 // indirect
github.com/libp2p/go-reuseport v0.1.0 // indirect
github.com/libp2p/go-reuseport-transport v0.1.0 // indirect
github.com/libp2p/go-stream-muxer-multistream v0.4.0 // indirect
github.com/libp2p/go-tcp-transport v0.5.1 // indirect
github.com/libp2p/go-ws-transport v0.6.1-0.20220221074654-eeaddb3c061d // indirect
github.com/libp2p/go-yamux/v3 v3.0.2 // indirect
github.com/lucas-clemente/quic-go v0.25.0 // indirect
github.com/marten-seemann/qtls-go1-16 v0.1.4 // indirect
github.com/marten-seemann/qtls-go1-17 v0.1.0 // indirect
github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1 // indirect
github.com/libp2p/go-reuseport v0.2.0 // indirect
github.com/libp2p/go-yamux/v3 v3.1.2 // indirect
github.com/lucas-clemente/quic-go v0.28.0 // indirect
github.com/marten-seemann/qtls-go1-16 v0.1.5 // indirect
github.com/marten-seemann/qtls-go1-17 v0.1.2 // indirect
github.com/marten-seemann/qtls-go1-18 v0.1.2 // indirect
github.com/marten-seemann/qtls-go1-19 v0.1.0-beta.1 // indirect
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect
github.com/mattn/go-colorable v0.1.8 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/miekg/dns v1.1.43 // indirect
github.com/mattn/go-sqlite3 v2.0.2+incompatible // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
github.com/miekg/dns v1.1.50 // indirect
github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect
github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect
github.com/minio/sha256-simd v1.0.0 // indirect
github.com/mr-tron/base58 v1.2.0 // indirect
github.com/mschoch/smat v0.2.0 // indirect
github.com/multiformats/go-base32 v0.0.3 // indirect
github.com/multiformats/go-base32 v0.0.4 // indirect
github.com/multiformats/go-base36 v0.1.0 // indirect
github.com/multiformats/go-multiaddr-dns v0.3.1 // indirect
github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect
github.com/multiformats/go-multistream v0.2.2 // indirect
github.com/multiformats/go-multicodec v0.5.0 // indirect
github.com/multiformats/go-multistream v0.3.3 // indirect
github.com/nxadm/tail v1.4.8 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/onsi/ginkgo v1.16.5 // indirect
github.com/opencontainers/runtime-spec v1.0.2 // indirect
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
github.com/peterh/liner v1.2.1 // indirect
@ -228,11 +215,11 @@ require (
github.com/pion/webrtc/v3 v3.1.24-0.20220208053747-94262c1b2b38 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.30.0 // indirect
github.com/prometheus/common v0.35.0 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
github.com/prometheus/tsdb v0.10.0 // indirect
github.com/raulk/clock v1.1.0 // indirect
github.com/raulk/go-watchdog v1.2.0 // indirect
github.com/raulk/go-watchdog v1.3.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/rjeczalik/notify v0.9.2 // indirect
@ -241,35 +228,39 @@ require (
github.com/russolsen/ohyeah v0.0.0-20160324131710-f4938c005315 // indirect
github.com/russolsen/same v0.0.0-20160222130632-f089df61f51d // indirect
github.com/shirou/gopsutil v3.21.5+incompatible // indirect
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 // indirect
github.com/shopspring/decimal v1.2.0 // indirect
github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect
github.com/status-im/go-discover v0.0.0-20220220162124-91b97a3e0efe // indirect
github.com/status-im/go-multiaddr-ethv4 v1.2.1 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/status-im/go-discover v0.0.0-20220406135310-85a2ce36f63e // indirect
github.com/status-im/go-multiaddr-ethv4 v1.2.3 // indirect
github.com/status-im/go-rln v0.0.9 // indirect
github.com/status-im/keycard-go v0.0.0-20200402102358-957c09536969 // indirect
github.com/tklauser/go-sysconf v0.3.6 // indirect
github.com/tklauser/numcpus v0.2.2 // indirect
github.com/tyler-smith/go-bip39 v1.1.0 // indirect
github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 // indirect
github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
go.etcd.io/bbolt v1.3.6 // indirect
go.opencensus.io v0.23.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.7.0 // indirect
golang.org/x/mod v0.4.2 // indirect
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect
go.uber.org/multierr v1.8.0 // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/net v0.0.0-20220630215102-69896b714898 // indirect
golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 // indirect
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
golang.org/x/tools v0.1.5 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 // indirect
golang.org/x/tools v0.1.11 // indirect
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect
google.golang.org/protobuf v1.28.0 // indirect
gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/urfave/cli.v1 v1.20.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/blake3 v1.1.7 // indirect
modernc.org/libc v1.11.82 // indirect
modernc.org/mathutil v1.4.1 // indirect
modernc.org/memory v1.0.5 // indirect

1371
go.sum

File diff suppressed because it is too large Load Diff

View File

@ -22,7 +22,7 @@ import (
func bindataRead(data []byte, name string) ([]byte, error) {
gz, err := gzip.NewReader(bytes.NewBuffer(data))
if err != nil {
return nil, fmt.Errorf("read %q: %v", name, err)
return nil, fmt.Errorf("read %q: %w", name, err)
}
var buf bytes.Buffer
@ -30,7 +30,7 @@ func bindataRead(data []byte, name string) ([]byte, error) {
clErr := gz.Close()
if err != nil {
return nil, fmt.Errorf("read %q: %v", name, err)
return nil, fmt.Errorf("read %q: %w", name, err)
}
if clErr != nil {
return nil, err
@ -223,12 +223,13 @@ func AssetNames() []string {
// _bindata is a table, holding each asset generator, mapped to its name.
var _bindata = map[string]func() (*asset, error){
"1557732988_initialize_db.down.sql": _1557732988_initialize_dbDownSql,
"1557732988_initialize_db.up.sql": _1557732988_initialize_dbUpSql,
"static.go": staticGo,
"1557732988_initialize_db.up.sql": _1557732988_initialize_dbUpSql,
"static.go": staticGo,
}
// AssetDebug is true if the assets were built with the debug flag enabled.
const AssetDebug = false
// AssetDir returns the file names below a certain
// directory embedded in the file by go-bindata.
// For example if you run go-bindata on data/... and data contains the
@ -270,9 +271,9 @@ type bintree struct {
}
var _bintree = &bintree{nil, map[string]*bintree{
"1557732988_initialize_db.down.sql": &bintree{_1557732988_initialize_dbDownSql, map[string]*bintree{}},
"1557732988_initialize_db.up.sql": &bintree{_1557732988_initialize_dbUpSql, map[string]*bintree{}},
"static.go": &bintree{staticGo, map[string]*bintree{}},
"1557732988_initialize_db.down.sql": {_1557732988_initialize_dbDownSql, map[string]*bintree{}},
"1557732988_initialize_db.up.sql": {_1557732988_initialize_dbUpSql, map[string]*bintree{}},
"static.go": {staticGo, map[string]*bintree{}},
}}
// RestoreAsset restores an asset under the given directory.

View File

@ -287,6 +287,9 @@ func (b *StatusNode) wakuV2Service(nodeConfig *params.NodeConfig) (*wakuv2.Waku,
Rendezvous: nodeConfig.Rendezvous,
WakuRendezvousNodes: nodeConfig.ClusterConfig.WakuRendezvousNodes,
PeerExchange: nodeConfig.WakuV2Config.PeerExchange,
EnableStore: nodeConfig.WakuV2Config.EnableStore,
StoreCapacity: nodeConfig.WakuV2Config.StoreCapacity,
StoreSeconds: nodeConfig.WakuV2Config.StoreSeconds,
DiscoveryLimit: nodeConfig.WakuV2Config.DiscoveryLimit,
PersistPeers: nodeConfig.WakuV2Config.PersistPeers,
DiscV5BootstrapNodes: nodeConfig.ClusterConfig.DiscV5BootstrapNodes,

View File

@ -272,6 +272,17 @@ func insertWakuV2Config(tx *sql.Tx, c *params.NodeConfig) error {
return nil
}
func insertWakuV2StoreConfig(tx *sql.Tx, c *params.NodeConfig) error {
_, err := tx.Exec(`
UPDATE wakuv2_config
SET enable_store = ?, store_capacity = ?, store_seconds = ?
WHERE synthetic_id = 'id'`,
c.WakuV2Config.EnableStore, c.WakuV2Config.StoreCapacity, c.WakuV2Config.StoreSeconds,
)
return err
}
func insertWakuConfig(tx *sql.Tx, c *params.NodeConfig) error {
_, err := tx.Exec(`
INSERT OR REPLACE INTO waku_config (
@ -390,6 +401,7 @@ func nodeConfigNormalInserts() []insertFn {
insertWakuConfig,
insertWakuV2Config,
insertTorrentConfig,
insertWakuV2StoreConfig,
}
}

View File

@ -203,6 +203,15 @@ type WakuV2Config struct {
// AutoUpdate instructs the node to update their own ip address and port with the values seen by other nodes
AutoUpdate bool
// EnableStore indicates if WakuStore protocol should be enabled or not
EnableStore bool
// StoreCapacity indicates the max number of messages to store
StoreCapacity int
// StoreSeconds indicates the maximum number of seconds before a message is removed from the store
StoreSeconds int
}
// ----------

View File

@ -1,12 +1,15 @@
clock
=====
[![go.dev reference](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white&style=flat-square)](https://pkg.go.dev/mod/github.com/benbjohnson/clock)
Clock is a small library for mocking time in Go. It provides an interface
around the standard library's [`time`][time] package so that the application
can use the realtime clock while tests can use the mock clock.
[time]: http://golang.org/pkg/time/
The module is currently maintained by @djmitche.
[time]: https://pkg.go.dev/github.com/benbjohnson/clock
## Usage
@ -86,7 +89,7 @@ count := 0
// Kick off a timer to increment every 1 mock second.
go func() {
ticker := clock.Ticker(1 * time.Second)
ticker := mock.Ticker(1 * time.Second)
for {
<-ticker.C
count++
@ -100,5 +103,3 @@ mock.Add(10 * time.Second)
// This prints 10.
fmt.Println(count)
```

View File

@ -1,11 +1,15 @@
package clock
import (
"context"
"sort"
"sync"
"time"
)
// Re-export of time.Duration
type Duration = time.Duration
// Clock represents an interface to the functions in the standard library time
// package. Two implementations are available in the clock package. The first
// is a real-time clock which simply wraps the time package's functions. The
@ -16,10 +20,13 @@ type Clock interface {
AfterFunc(d time.Duration, f func()) *Timer
Now() time.Time
Since(t time.Time) time.Duration
Until(t time.Time) time.Duration
Sleep(d time.Duration)
Tick(d time.Duration) <-chan time.Time
Ticker(d time.Duration) *Ticker
Timer(d time.Duration) *Timer
WithDeadline(parent context.Context, d time.Time) (context.Context, context.CancelFunc)
WithTimeout(parent context.Context, t time.Duration) (context.Context, context.CancelFunc)
}
// New returns an instance of a real-time clock.
@ -40,6 +47,8 @@ func (c *clock) Now() time.Time { return time.Now() }
func (c *clock) Since(t time.Time) time.Duration { return time.Since(t) }
func (c *clock) Until(t time.Time) time.Duration { return time.Until(t) }
func (c *clock) Sleep(d time.Duration) { time.Sleep(d) }
func (c *clock) Tick(d time.Duration) <-chan time.Time { return time.Tick(d) }
@ -54,7 +63,15 @@ func (c *clock) Timer(d time.Duration) *Timer {
return &Timer{C: t.C, timer: t}
}
// Mock represents a mock clock that only moves forward programmatically.
func (c *clock) WithDeadline(parent context.Context, d time.Time) (context.Context, context.CancelFunc) {
return context.WithDeadline(parent, d)
}
func (c *clock) WithTimeout(parent context.Context, t time.Duration) (context.Context, context.CancelFunc) {
return context.WithTimeout(parent, t)
}
// Mock represents a mock clock that only moves forward programmically.
// It can be preferable to a real-time clock when testing time-based functionality.
type Mock struct {
mu sync.Mutex
@ -161,11 +178,16 @@ func (m *Mock) Now() time.Time {
return m.now
}
// Since returns time since the mock clock's wall time.
// Since returns time since `t` using the mock clock's wall time.
func (m *Mock) Since(t time.Time) time.Duration {
return m.Now().Sub(t)
}
// Until returns time until `t` using the mock clock's wall time.
func (m *Mock) Until(t time.Time) time.Duration {
return t.Sub(m.Now())
}
// Sleep pauses the goroutine for the given duration on the mock clock.
// The clock must be moved forward in a separate goroutine.
func (m *Mock) Sleep(d time.Duration) {
@ -284,16 +306,20 @@ type internalTimer Timer
func (t *internalTimer) Next() time.Time { return t.next }
func (t *internalTimer) Tick(now time.Time) {
// a gosched() after ticking, to allow any consequences of the
// tick to complete
defer gosched()
t.mock.mu.Lock()
if t.fn != nil {
t.fn()
// defer function execution until the lock is released, and
defer t.fn()
} else {
t.c <- now
}
t.mock.removeClockTimer((*internalTimer)(t))
t.stopped = true
t.mock.mu.Unlock()
gosched()
}
// Ticker holds a channel that receives "ticks" at regular intervals.
@ -321,7 +347,14 @@ func (t *Ticker) Stop() {
func (t *Ticker) Reset(dur time.Duration) {
if t.ticker != nil {
t.ticker.Reset(dur)
return
}
t.mock.mu.Lock()
defer t.mock.mu.Unlock()
t.d = dur
t.next = t.mock.now.Add(dur)
}
type internalTicker Ticker
@ -338,3 +371,8 @@ func (t *internalTicker) Tick(now time.Time) {
// Sleep momentarily so that other goroutines can process.
func gosched() { time.Sleep(1 * time.Millisecond) }
var (
// type checking
_ Clock = &Mock{}
)

86
vendor/github.com/benbjohnson/clock/context.go generated vendored Normal file
View File

@ -0,0 +1,86 @@
package clock
import (
"context"
"fmt"
"sync"
"time"
)
func (m *Mock) WithTimeout(parent context.Context, timeout time.Duration) (context.Context, context.CancelFunc) {
return m.WithDeadline(parent, m.Now().Add(timeout))
}
func (m *Mock) WithDeadline(parent context.Context, deadline time.Time) (context.Context, context.CancelFunc) {
if cur, ok := parent.Deadline(); ok && cur.Before(deadline) {
// The current deadline is already sooner than the new one.
return context.WithCancel(parent)
}
ctx := &timerCtx{clock: m, parent: parent, deadline: deadline, done: make(chan struct{})}
propagateCancel(parent, ctx)
dur := m.Until(deadline)
if dur <= 0 {
ctx.cancel(context.DeadlineExceeded) // deadline has already passed
return ctx, func() {}
}
ctx.Lock()
defer ctx.Unlock()
if ctx.err == nil {
ctx.timer = m.AfterFunc(dur, func() {
ctx.cancel(context.DeadlineExceeded)
})
}
return ctx, func() { ctx.cancel(context.Canceled) }
}
// propagateCancel arranges for child to be canceled when parent is.
func propagateCancel(parent context.Context, child *timerCtx) {
if parent.Done() == nil {
return // parent is never canceled
}
go func() {
select {
case <-parent.Done():
child.cancel(parent.Err())
case <-child.Done():
}
}()
}
type timerCtx struct {
sync.Mutex
clock Clock
parent context.Context
deadline time.Time
done chan struct{}
err error
timer *Timer
}
func (c *timerCtx) cancel(err error) {
c.Lock()
defer c.Unlock()
if c.err != nil {
return // already canceled
}
c.err = err
close(c.done)
if c.timer != nil {
c.timer.Stop()
c.timer = nil
}
}
func (c *timerCtx) Deadline() (deadline time.Time, ok bool) { return c.deadline, true }
func (c *timerCtx) Done() <-chan struct{} { return c.done }
func (c *timerCtx) Err() error { return c.err }
func (c *timerCtx) Value(key interface{}) interface{} { return c.parent.Value(key) }
func (c *timerCtx) String() string {
return fmt.Sprintf("clock.WithDeadline(%s [%s])", c.deadline, c.deadline.Sub(c.clock.Now()))
}

16
vendor/github.com/btcsuite/btcd/btcec/v2/LICENSE generated vendored Normal file
View File

@ -0,0 +1,16 @@
ISC License
Copyright (c) 2013-2022 The btcsuite developers
Copyright (c) 2015-2016 The Decred developers
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

40
vendor/github.com/btcsuite/btcd/btcec/v2/README.md generated vendored Normal file
View File

@ -0,0 +1,40 @@
btcec
=====
[![Build Status](https://github.com/btcsuite/btcd/workflows/Build%20and%20Test/badge.svg)](https://github.com/btcsuite/btcd/actions)
[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
[![GoDoc](https://pkg.go.dev/github.com/btcsuite/btcd/btcec/v2?status.png)](https://pkg.go.dev/github.com/btcsuite/btcd/btcec/v2)
Package btcec implements elliptic curve cryptography needed for working with
Bitcoin (secp256k1 only for now). It is designed so that it may be used with the
standard crypto/ecdsa packages provided with go. A comprehensive suite of test
is provided to ensure proper functionality. Package btcec was originally based
on work from ThePiachu which is licensed under the same terms as Go, but it has
signficantly diverged since then. The btcsuite developers original is licensed
under the liberal ISC license.
Although this package was primarily written for btcd, it has intentionally been
designed so it can be used as a standalone package for any projects needing to
use secp256k1 elliptic curve cryptography.
## Installation and Updating
```bash
$ go install -u -v github.com/btcsuite/btcd/btcec/v2
```
## Examples
* [Sign Message](https://pkg.go.dev/github.com/btcsuite/btcd/btcec/v2#example-package--SignMessage)
Demonstrates signing a message with a secp256k1 private key that is first
parsed form raw bytes and serializing the generated signature.
* [Verify Signature](https://pkg.go.dev/github.com/btcsuite/btcd/btcec/v2#example-package--VerifySignature)
Demonstrates verifying a secp256k1 signature against a public key that is
first parsed from raw bytes. The signature is also parsed from raw bytes.
## License
Package btcec is licensed under the [copyfree](http://copyfree.org) ISC License
except for btcec.go and btcec_test.go which is under the same license as Go.

41
vendor/github.com/btcsuite/btcd/btcec/v2/btcec.go generated vendored Normal file
View File

@ -0,0 +1,41 @@
// Copyright 2010 The Go Authors. All rights reserved.
// Copyright 2011 ThePiachu. All rights reserved.
// Copyright 2013-2014 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package btcec
// References:
// [SECG]: Recommended Elliptic Curve Domain Parameters
// http://www.secg.org/sec2-v2.pdf
//
// [GECC]: Guide to Elliptic Curve Cryptography (Hankerson, Menezes, Vanstone)
// This package operates, internally, on Jacobian coordinates. For a given
// (x, y) position on the curve, the Jacobian coordinates are (x1, y1, z1)
// where x = x1/z1² and y = y1/z1³. The greatest speedups come when the whole
// calculation can be performed within the transform (as in ScalarMult and
// ScalarBaseMult). But even for Add and Double, it's faster to apply and
// reverse the transform than to operate in affine coordinates.
import (
secp "github.com/decred/dcrd/dcrec/secp256k1/v4"
)
// KoblitzCurve provides an implementation for secp256k1 that fits the ECC
// Curve interface from crypto/elliptic.
type KoblitzCurve = secp.KoblitzCurve
// S256 returns a Curve which implements secp256k1.
func S256() *KoblitzCurve {
return secp.S256()
}
// CurveParams contains the parameters for the secp256k1 curve.
type CurveParams = secp.CurveParams
// Params returns the secp256k1 curve parameters for convenience.
func Params() *CurveParams {
return secp.Params()
}

16
vendor/github.com/btcsuite/btcd/btcec/v2/ciphering.go generated vendored Normal file
View File

@ -0,0 +1,16 @@
// Copyright (c) 2015-2016 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package btcec
import (
secp "github.com/decred/dcrd/dcrec/secp256k1/v4"
)
// GenerateSharedSecret generates a shared secret based on a private key and a
// public key using Diffie-Hellman key exchange (ECDH) (RFC 4753).
// RFC5903 Section 9 states we should only return x.
func GenerateSharedSecret(privkey *PrivateKey, pubkey *PublicKey) []byte {
return secp.GenerateSharedSecret(privkey, pubkey)
}

63
vendor/github.com/btcsuite/btcd/btcec/v2/curve.go generated vendored Normal file
View File

@ -0,0 +1,63 @@
// Copyright (c) 2015-2021 The btcsuite developers
// Copyright (c) 2015-2021 The Decred developers
package btcec
import (
secp "github.com/decred/dcrd/dcrec/secp256k1/v4"
)
// JacobianPoint is an element of the group formed by the secp256k1 curve in
// Jacobian projective coordinates and thus represents a point on the curve.
type JacobianPoint = secp.JacobianPoint
// MakeJacobianPoint returns a Jacobian point with the provided X, Y, and Z
// coordinates.
func MakeJacobianPoint(x, y, z *FieldVal) JacobianPoint {
return secp.MakeJacobianPoint(x, y, z)
}
// AddNonConst adds the passed Jacobian points together and stores the result
// in the provided result param in *non-constant* time.
func AddNonConst(p1, p2, result *JacobianPoint) {
secp.AddNonConst(p1, p2, result)
}
// DecompressY attempts to calculate the Y coordinate for the given X
// coordinate such that the result pair is a point on the secp256k1 curve. It
// adjusts Y based on the desired oddness and returns whether or not it was
// successful since not all X coordinates are valid.
//
// The magnitude of the provided X coordinate field val must be a max of 8 for
// a correct result. The resulting Y field val will have a max magnitude of 2.
func DecompressY(x *FieldVal, odd bool, resultY *FieldVal) bool {
return secp.DecompressY(x, odd, resultY)
}
// DoubleNonConst doubles the passed Jacobian point and stores the result in
// the provided result parameter in *non-constant* time.
//
// NOTE: The point must be normalized for this function to return the correct
// result. The resulting point will be normalized.
func DoubleNonConst(p, result *JacobianPoint) {
secp.DoubleNonConst(p, result)
}
// ScalarBaseMultNonConst multiplies k*G where G is the base point of the group
// and k is a big endian integer. The result is stored in Jacobian coordinates
// (x1, y1, z1).
//
// NOTE: The resulting point will be normalized.
func ScalarBaseMultNonConst(k *ModNScalar, result *JacobianPoint) {
secp.ScalarBaseMultNonConst(k, result)
}
// ScalarMultNonConst multiplies k*P where k is a big endian integer modulo the
// curve order and P is a point in Jacobian projective coordinates and stores
// the result in the provided Jacobian point.
//
// NOTE: The point must be normalized for this function to return the correct
// result. The resulting point will be normalized.
func ScalarMultNonConst(k *ModNScalar, point, result *JacobianPoint) {
secp.ScalarMultNonConst(k, point, result)
}

21
vendor/github.com/btcsuite/btcd/btcec/v2/doc.go generated vendored Normal file
View File

@ -0,0 +1,21 @@
// Copyright (c) 2013-2014 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
/*
Package btcec implements support for the elliptic curves needed for bitcoin.
Bitcoin uses elliptic curve cryptography using koblitz curves
(specifically secp256k1) for cryptographic functions. See
http://www.secg.org/collateral/sec2_final.pdf for details on the
standard.
This package provides the data structures and functions implementing the
crypto/elliptic Curve interface in order to permit using these curves
with the standard crypto/ecdsa package provided with go. Helper
functionality is provided to parse signatures and public keys from
standard formats. It was designed for use with btcd, but should be
general enough for other uses of elliptic curve crypto. It was originally based
on some initial work by ThePiachu, but has significantly diverged since then.
*/
package btcec

View File

@ -0,0 +1,18 @@
// Copyright (c) 2013-2021 The btcsuite developers
// Copyright (c) 2015-2021 The Decred developers
package ecdsa
import (
secp_ecdsa "github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa"
)
// ErrorKind identifies a kind of error. It has full support for
// errors.Is and errors.As, so the caller can directly check against
// an error kind when determining the reason for an error.
type ErrorKind = secp_ecdsa.ErrorKind
// Error identifies an error related to an ECDSA signature. It has full
// support for errors.Is and errors.As, so the caller can ascertain the
// specific reason for the error by checking the underlying error.
type Error = secp_ecdsa.ErrorKind

View File

@ -0,0 +1,240 @@
// Copyright (c) 2013-2017 The btcsuite developers
// Copyright (c) 2015-2021 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package ecdsa
import (
"errors"
"fmt"
"math/big"
"github.com/btcsuite/btcd/btcec/v2"
secp_ecdsa "github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa"
)
// Errors returned by canonicalPadding.
var (
errNegativeValue = errors.New("value may be interpreted as negative")
errExcessivelyPaddedValue = errors.New("value is excessively padded")
)
// Signature is a type representing an ecdsa signature.
type Signature = secp_ecdsa.Signature
// NewSignature instantiates a new signature given some r and s values.
func NewSignature(r, s *btcec.ModNScalar) *Signature {
return secp_ecdsa.NewSignature(r, s)
}
var (
// Used in RFC6979 implementation when testing the nonce for correctness
one = big.NewInt(1)
// oneInitializer is used to fill a byte slice with byte 0x01. It is provided
// here to avoid the need to create it multiple times.
oneInitializer = []byte{0x01}
)
// MinSigLen is the minimum length of a DER encoded signature and is when both R
// and S are 1 byte each.
// 0x30 + <1-byte> + 0x02 + 0x01 + <byte> + 0x2 + 0x01 + <byte>
const MinSigLen = 8
// canonicalPadding checks whether a big-endian encoded integer could
// possibly be misinterpreted as a negative number (even though OpenSSL
// treats all numbers as unsigned), or if there is any unnecessary
// leading zero padding.
func canonicalPadding(b []byte) error {
switch {
case b[0]&0x80 == 0x80:
return errNegativeValue
case len(b) > 1 && b[0] == 0x00 && b[1]&0x80 != 0x80:
return errExcessivelyPaddedValue
default:
return nil
}
}
func parseSig(sigStr []byte, der bool) (*Signature, error) {
// Originally this code used encoding/asn1 in order to parse the
// signature, but a number of problems were found with this approach.
// Despite the fact that signatures are stored as DER, the difference
// between go's idea of a bignum (and that they have sign) doesn't agree
// with the openssl one (where they do not). The above is true as of
// Go 1.1. In the end it was simpler to rewrite the code to explicitly
// understand the format which is this:
// 0x30 <length of whole message> <0x02> <length of R> <R> 0x2
// <length of S> <S>.
if len(sigStr) < MinSigLen {
return nil, errors.New("malformed signature: too short")
}
// 0x30
index := 0
if sigStr[index] != 0x30 {
return nil, errors.New("malformed signature: no header magic")
}
index++
// length of remaining message
siglen := sigStr[index]
index++
// siglen should be less than the entire message and greater than
// the minimal message size.
if int(siglen+2) > len(sigStr) || int(siglen+2) < MinSigLen {
return nil, errors.New("malformed signature: bad length")
}
// trim the slice we're working on so we only look at what matters.
sigStr = sigStr[:siglen+2]
// 0x02
if sigStr[index] != 0x02 {
return nil,
errors.New("malformed signature: no 1st int marker")
}
index++
// Length of signature R.
rLen := int(sigStr[index])
// must be positive, must be able to fit in another 0x2, <len> <s>
// hence the -3. We assume that the length must be at least one byte.
index++
if rLen <= 0 || rLen > len(sigStr)-index-3 {
return nil, errors.New("malformed signature: bogus R length")
}
// Then R itself.
rBytes := sigStr[index : index+rLen]
if der {
switch err := canonicalPadding(rBytes); err {
case errNegativeValue:
return nil, errors.New("signature R is negative")
case errExcessivelyPaddedValue:
return nil, errors.New("signature R is excessively padded")
}
}
// Strip leading zeroes from R.
for len(rBytes) > 0 && rBytes[0] == 0x00 {
rBytes = rBytes[1:]
}
// R must be in the range [1, N-1]. Notice the check for the maximum number
// of bytes is required because SetByteSlice truncates as noted in its
// comment so it could otherwise fail to detect the overflow.
var r btcec.ModNScalar
if len(rBytes) > 32 {
str := "invalid signature: R is larger than 256 bits"
return nil, errors.New(str)
}
if overflow := r.SetByteSlice(rBytes); overflow {
str := "invalid signature: R >= group order"
return nil, errors.New(str)
}
if r.IsZero() {
str := "invalid signature: R is 0"
return nil, errors.New(str)
}
index += rLen
// 0x02. length already checked in previous if.
if sigStr[index] != 0x02 {
return nil, errors.New("malformed signature: no 2nd int marker")
}
index++
// Length of signature S.
sLen := int(sigStr[index])
index++
// S should be the rest of the string.
if sLen <= 0 || sLen > len(sigStr)-index {
return nil, errors.New("malformed signature: bogus S length")
}
// Then S itself.
sBytes := sigStr[index : index+sLen]
if der {
switch err := canonicalPadding(sBytes); err {
case errNegativeValue:
return nil, errors.New("signature S is negative")
case errExcessivelyPaddedValue:
return nil, errors.New("signature S is excessively padded")
}
}
// Strip leading zeroes from S.
for len(sBytes) > 0 && sBytes[0] == 0x00 {
sBytes = sBytes[1:]
}
// S must be in the range [1, N-1]. Notice the check for the maximum number
// of bytes is required because SetByteSlice truncates as noted in its
// comment so it could otherwise fail to detect the overflow.
var s btcec.ModNScalar
if len(sBytes) > 32 {
str := "invalid signature: S is larger than 256 bits"
return nil, errors.New(str)
}
if overflow := s.SetByteSlice(sBytes); overflow {
str := "invalid signature: S >= group order"
return nil, errors.New(str)
}
if s.IsZero() {
str := "invalid signature: S is 0"
return nil, errors.New(str)
}
index += sLen
// sanity check length parsing
if index != len(sigStr) {
return nil, fmt.Errorf("malformed signature: bad final length %v != %v",
index, len(sigStr))
}
return NewSignature(&r, &s), nil
}
// ParseSignature parses a signature in BER format for the curve type `curve'
// into a Signature type, perfoming some basic sanity checks. If parsing
// according to the more strict DER format is needed, use ParseDERSignature.
func ParseSignature(sigStr []byte) (*Signature, error) {
return parseSig(sigStr, false)
}
// ParseDERSignature parses a signature in DER format for the curve type
// `curve` into a Signature type. If parsing according to the less strict
// BER format is needed, use ParseSignature.
func ParseDERSignature(sigStr []byte) (*Signature, error) {
return parseSig(sigStr, true)
}
// SignCompact produces a compact signature of the data in hash with the given
// private key on the given koblitz curve. The isCompressed parameter should
// be used to detail if the given signature should reference a compressed
// public key or not. If successful the bytes of the compact signature will be
// returned in the format:
// <(byte of 27+public key solution)+4 if compressed >< padded bytes for signature R><padded bytes for signature S>
// where the R and S parameters are padde up to the bitlengh of the curve.
func SignCompact(key *btcec.PrivateKey, hash []byte,
isCompressedKey bool) ([]byte, error) {
return secp_ecdsa.SignCompact(key, hash, isCompressedKey), nil
}
// RecoverCompact verifies the compact signature "signature" of "hash" for the
// Koblitz curve in "curve". If the signature matches then the recovered public
// key will be returned as well as a boolean if the original key was compressed
// or not, else an error will be returned.
func RecoverCompact(signature, hash []byte) (*btcec.PublicKey, bool, error) {
return secp_ecdsa.RecoverCompact(signature, hash)
}
// Sign generates an ECDSA signature over the secp256k1 curve for the provided
// hash (which should be the result of hashing a larger message) using the
// given private key. The produced signature is deterministic (same message and
// same key yield the same signature) and canonical in accordance with RFC6979
// and BIP0062.
func Sign(key *btcec.PrivateKey, hash []byte) *Signature {
return secp_ecdsa.Sign(key, hash)
}

19
vendor/github.com/btcsuite/btcd/btcec/v2/error.go generated vendored Normal file
View File

@ -0,0 +1,19 @@
// Copyright (c) 2013-2021 The btcsuite developers
// Copyright (c) 2015-2021 The Decred developers
package btcec
import (
secp "github.com/decred/dcrd/dcrec/secp256k1/v4"
)
// Error identifies an error related to public key cryptography using a
// sec256k1 curve. It has full support for errors.Is and errors.As, so the
// caller can ascertain the specific reason for the error by checking the
// underlying error.
type Error = secp.Error
// ErrorKind identifies a kind of error. It has full support for errors.Is and
// errors.As, so the caller can directly check against an error kind when
// determining the reason for an error.
type ErrorKind = secp.ErrorKind

43
vendor/github.com/btcsuite/btcd/btcec/v2/field.go generated vendored Normal file
View File

@ -0,0 +1,43 @@
package btcec
import secp "github.com/decred/dcrd/dcrec/secp256k1/v4"
// FieldVal implements optimized fixed-precision arithmetic over the secp256k1
// finite field. This means all arithmetic is performed modulo
// '0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f'.
//
// WARNING: Since it is so important for the field arithmetic to be extremely
// fast for high performance crypto, this type does not perform any validation
// of documented preconditions where it ordinarily would. As a result, it is
// IMPERATIVE for callers to understand some key concepts that are described
// below and ensure the methods are called with the necessary preconditions
// that each method is documented with. For example, some methods only give the
// correct result if the field value is normalized and others require the field
// values involved to have a maximum magnitude and THERE ARE NO EXPLICIT CHECKS
// TO ENSURE THOSE PRECONDITIONS ARE SATISFIED. This does, unfortunately, make
// the type more difficult to use correctly and while I typically prefer to
// ensure all state and input is valid for most code, this is a bit of an
// exception because those extra checks really add up in what ends up being
// critical hot paths.
//
// The first key concept when working with this type is normalization. In order
// to avoid the need to propagate a ton of carries, the internal representation
// provides additional overflow bits for each word of the overall 256-bit
// value. This means that there are multiple internal representations for the
// same value and, as a result, any methods that rely on comparison of the
// value, such as equality and oddness determination, require the caller to
// provide a normalized value.
//
// The second key concept when working with this type is magnitude. As
// previously mentioned, the internal representation provides additional
// overflow bits which means that the more math operations that are performed
// on the field value between normalizations, the more those overflow bits
// accumulate. The magnitude is effectively that maximum possible number of
// those overflow bits that could possibly be required as a result of a given
// operation. Since there are only a limited number of overflow bits available,
// this implies that the max possible magnitude MUST be tracked by the caller
// and the caller MUST normalize the field value if a given operation would
// cause the magnitude of the result to exceed the max allowed value.
//
// IMPORTANT: The max allowed magnitude of a field value is 64.
type FieldVal = secp.FieldVal

45
vendor/github.com/btcsuite/btcd/btcec/v2/modnscalar.go generated vendored Normal file
View File

@ -0,0 +1,45 @@
// Copyright (c) 2013-2021 The btcsuite developers
// Copyright (c) 2015-2021 The Decred developers
package btcec
import (
secp "github.com/decred/dcrd/dcrec/secp256k1/v4"
)
// ModNScalar implements optimized 256-bit constant-time fixed-precision
// arithmetic over the secp256k1 group order. This means all arithmetic is
// performed modulo:
//
// 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141
//
// It only implements the arithmetic needed for elliptic curve operations,
// however, the operations that are not implemented can typically be worked
// around if absolutely needed. For example, subtraction can be performed by
// adding the negation.
//
// Should it be absolutely necessary, conversion to the standard library
// math/big.Int can be accomplished by using the Bytes method, slicing the
// resulting fixed-size array, and feeding it to big.Int.SetBytes. However,
// that should typically be avoided when possible as conversion to big.Ints
// requires allocations, is not constant time, and is slower when working modulo
// the group order.
type ModNScalar = secp.ModNScalar
// NonceRFC6979 generates a nonce deterministically according to RFC 6979 using
// HMAC-SHA256 for the hashing function. It takes a 32-byte hash as an input
// and returns a 32-byte nonce to be used for deterministic signing. The extra
// and version arguments are optional, but allow additional data to be added to
// the input of the HMAC. When provided, the extra data must be 32-bytes and
// version must be 16 bytes or they will be ignored.
//
// Finally, the extraIterations parameter provides a method to produce a stream
// of deterministic nonces to ensure the signing code is able to produce a nonce
// that results in a valid signature in the extremely unlikely event the
// original nonce produced results in an invalid signature (e.g. R == 0).
// Signing code should start with 0 and increment it if necessary.
func NonceRFC6979(privKey []byte, hash []byte, extra []byte, version []byte,
extraIterations uint32) *ModNScalar {
return secp.NonceRFC6979(privKey, hash, extra, version, extraIterations)
}

37
vendor/github.com/btcsuite/btcd/btcec/v2/privkey.go generated vendored Normal file
View File

@ -0,0 +1,37 @@
// Copyright (c) 2013-2016 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package btcec
import (
secp "github.com/decred/dcrd/dcrec/secp256k1/v4"
)
// PrivateKey wraps an ecdsa.PrivateKey as a convenience mainly for signing
// things with the the private key without having to directly import the ecdsa
// package.
type PrivateKey = secp.PrivateKey
// PrivKeyFromBytes returns a private and public key for `curve' based on the
// private key passed as an argument as a byte slice.
func PrivKeyFromBytes(pk []byte) (*PrivateKey, *PublicKey) {
privKey := secp.PrivKeyFromBytes(pk)
return privKey, privKey.PubKey()
}
// NewPrivateKey is a wrapper for ecdsa.GenerateKey that returns a PrivateKey
// instead of the normal ecdsa.PrivateKey.
func NewPrivateKey() (*PrivateKey, error) {
return secp.GeneratePrivateKey()
}
// PrivKeyFromScalar instantiates a new private key from a scalar encoded as a
// big integer.
func PrivKeyFromScalar(key *ModNScalar) *PrivateKey {
return &PrivateKey{Key: *key}
}
// PrivKeyBytesLen defines the length in bytes of a serialized private key.
const PrivKeyBytesLen = 32

51
vendor/github.com/btcsuite/btcd/btcec/v2/pubkey.go generated vendored Normal file
View File

@ -0,0 +1,51 @@
// Copyright (c) 2013-2014 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package btcec
import (
secp "github.com/decred/dcrd/dcrec/secp256k1/v4"
)
// These constants define the lengths of serialized public keys.
const (
PubKeyBytesLenCompressed = 33
)
const (
pubkeyCompressed byte = 0x2 // y_bit + x coord
pubkeyUncompressed byte = 0x4 // x coord + y coord
pubkeyHybrid byte = 0x6 // y_bit + x coord + y coord
)
// IsCompressedPubKey returns true the the passed serialized public key has
// been encoded in compressed format, and false otherwise.
func IsCompressedPubKey(pubKey []byte) bool {
// The public key is only compressed if it is the correct length and
// the format (first byte) is one of the compressed pubkey values.
return len(pubKey) == PubKeyBytesLenCompressed &&
(pubKey[0]&^byte(0x1) == pubkeyCompressed)
}
// ParsePubKey parses a public key for a koblitz curve from a bytestring into a
// ecdsa.Publickey, verifying that it is valid. It supports compressed,
// uncompressed and hybrid signature formats.
func ParsePubKey(pubKeyStr []byte) (*PublicKey, error) {
return secp.ParsePubKey(pubKeyStr)
}
// PublicKey is an ecdsa.PublicKey with additional functions to
// serialize in uncompressed, compressed, and hybrid formats.
type PublicKey = secp.PublicKey
// NewPublicKey instantiates a new public key with the given x and y
// coordinates.
//
// It should be noted that, unlike ParsePubKey, since this accepts arbitrary x
// and y coordinates, it allows creation of public keys that are not valid
// points on the secp256k1 curve. The IsOnCurve method of the returned instance
// can be used to determine validity.
func NewPublicKey(x, y *FieldVal) *PublicKey {
return secp.NewPublicKey(x, y)
}

View File

@ -0,0 +1,16 @@
ISC License
Copyright (c) 2013-2022 The btcsuite developers
Copyright (c) 2015-2016 The Decred developers
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

View File

@ -6,6 +6,7 @@
package chainhash
import (
"crypto/sha256"
"encoding/hex"
"fmt"
)
@ -16,6 +17,46 @@ const HashSize = 32
// MaxHashStringSize is the maximum length of a Hash hash string.
const MaxHashStringSize = HashSize * 2
var (
// TagBIP0340Challenge is the BIP-0340 tag for challenges.
TagBIP0340Challenge = []byte("BIP0340/challenge")
// TagBIP0340Aux is the BIP-0340 tag for aux data.
TagBIP0340Aux = []byte("BIP0340/aux")
// TagBIP0340Nonce is the BIP-0340 tag for nonces.
TagBIP0340Nonce = []byte("BIP0340/nonce")
// TagTapSighash is the tag used by BIP 341 to generate the sighash
// flags.
TagTapSighash = []byte("TapSighash")
// TagTagTapLeaf is the message tag prefix used to compute the hash
// digest of a tapscript leaf.
TagTapLeaf = []byte("TapLeaf")
// TagTapBranch is the message tag prefix used to compute the
// hash digest of two tap leaves into a taproot branch node.
TagTapBranch = []byte("TapBranch")
// TagTapTweak is the message tag prefix used to compute the hash tweak
// used to enable a public key to commit to the taproot branch root
// for the witness program.
TagTapTweak = []byte("TapTweak")
// precomputedTags is a map containing the SHA-256 hash of the BIP-0340
// tags.
precomputedTags = map[string]Hash{
string(TagBIP0340Challenge): sha256.Sum256(TagBIP0340Challenge),
string(TagBIP0340Aux): sha256.Sum256(TagBIP0340Aux),
string(TagBIP0340Nonce): sha256.Sum256(TagBIP0340Nonce),
string(TagTapSighash): sha256.Sum256(TagTapSighash),
string(TagTapLeaf): sha256.Sum256(TagTapLeaf),
string(TagTapBranch): sha256.Sum256(TagTapBranch),
string(TagTapTweak): sha256.Sum256(TagTapTweak),
}
)
// ErrHashStrSize describes an error that indicates the caller specified a hash
// string that has too many characters.
var ErrHashStrSize = fmt.Errorf("max hash string length is %v bytes", MaxHashStringSize)
@ -80,6 +121,35 @@ func NewHash(newHash []byte) (*Hash, error) {
return &sh, err
}
// TaggedHash implements the tagged hash scheme described in BIP-340. We use
// sha-256 to bind a message hash to a specific context using a tag:
// sha256(sha256(tag) || sha256(tag) || msg).
func TaggedHash(tag []byte, msgs ...[]byte) *Hash {
// Check to see if we've already pre-computed the hash of the tag. If
// so then this'll save us an extra sha256 hash.
shaTag, ok := precomputedTags[string(tag)]
if !ok {
shaTag = sha256.Sum256(tag)
}
// h = sha256(sha256(tag) || sha256(tag) || msg)
h := sha256.New()
h.Write(shaTag[:])
h.Write(shaTag[:])
for _, msg := range msgs {
h.Write(msg)
}
taggedHash := h.Sum(nil)
// The function can't error out since the above hash is guaranteed to
// be 32 bytes.
hash, _ := NewHash(taggedHash)
return hash
}
// NewHashFromStr creates a Hash from a hash string. The string should be
// the hexadecimal string of a byte-reversed hash, but any missing characters
// result in zero padding at the end of the Hash.

View File

@ -1,8 +0,0 @@
language: go
go:
- "1.x"
- master
env:
- TAGS=""
- TAGS="-tags purego"
script: go test $TAGS -v ./...

View File

@ -1,7 +1,7 @@
# xxhash
[![GoDoc](https://godoc.org/github.com/cespare/xxhash?status.svg)](https://godoc.org/github.com/cespare/xxhash)
[![Build Status](https://travis-ci.org/cespare/xxhash.svg?branch=master)](https://travis-ci.org/cespare/xxhash)
[![Go Reference](https://pkg.go.dev/badge/github.com/cespare/xxhash/v2.svg)](https://pkg.go.dev/github.com/cespare/xxhash/v2)
[![Test](https://github.com/cespare/xxhash/actions/workflows/test.yml/badge.svg)](https://github.com/cespare/xxhash/actions/workflows/test.yml)
xxhash is a Go implementation of the 64-bit
[xxHash](http://cyan4973.github.io/xxHash/) algorithm, XXH64. This is a
@ -64,4 +64,6 @@ $ go test -benchtime 10s -bench '/xxhash,direct,bytes'
- [InfluxDB](https://github.com/influxdata/influxdb)
- [Prometheus](https://github.com/prometheus/prometheus)
- [VictoriaMetrics](https://github.com/VictoriaMetrics/VictoriaMetrics)
- [FreeCache](https://github.com/coocood/freecache)
- [FastCache](https://github.com/VictoriaMetrics/fastcache)

View File

@ -193,7 +193,6 @@ func (d *Digest) UnmarshalBinary(b []byte) error {
b, d.v4 = consumeUint64(b)
b, d.total = consumeUint64(b)
copy(d.mem[:], b)
b = b[len(d.mem):]
d.n = int(d.total % uint64(len(d.mem)))
return nil
}

View File

@ -6,7 +6,7 @@
// Register allocation:
// AX h
// CX pointer to advance through b
// SI pointer to advance through b
// DX n
// BX loop end
// R8 v1, k1
@ -16,39 +16,39 @@
// R12 tmp
// R13 prime1v
// R14 prime2v
// R15 prime4v
// DI prime4v
// round reads from and advances the buffer pointer in CX.
// round reads from and advances the buffer pointer in SI.
// It assumes that R13 has prime1v and R14 has prime2v.
#define round(r) \
MOVQ (CX), R12 \
ADDQ $8, CX \
MOVQ (SI), R12 \
ADDQ $8, SI \
IMULQ R14, R12 \
ADDQ R12, r \
ROLQ $31, r \
IMULQ R13, r
// mergeRound applies a merge round on the two registers acc and val.
// It assumes that R13 has prime1v, R14 has prime2v, and R15 has prime4v.
// It assumes that R13 has prime1v, R14 has prime2v, and DI has prime4v.
#define mergeRound(acc, val) \
IMULQ R14, val \
ROLQ $31, val \
IMULQ R13, val \
XORQ val, acc \
IMULQ R13, acc \
ADDQ R15, acc
ADDQ DI, acc
// func Sum64(b []byte) uint64
TEXT ·Sum64(SB), NOSPLIT, $0-32
// Load fixed primes.
MOVQ ·prime1v(SB), R13
MOVQ ·prime2v(SB), R14
MOVQ ·prime4v(SB), R15
MOVQ ·prime4v(SB), DI
// Load slice.
MOVQ b_base+0(FP), CX
MOVQ b_base+0(FP), SI
MOVQ b_len+8(FP), DX
LEAQ (CX)(DX*1), BX
LEAQ (SI)(DX*1), BX
// The first loop limit will be len(b)-32.
SUBQ $32, BX
@ -65,14 +65,14 @@ TEXT ·Sum64(SB), NOSPLIT, $0-32
XORQ R11, R11
SUBQ R13, R11
// Loop until CX > BX.
// Loop until SI > BX.
blockLoop:
round(R8)
round(R9)
round(R10)
round(R11)
CMPQ CX, BX
CMPQ SI, BX
JLE blockLoop
MOVQ R8, AX
@ -100,16 +100,16 @@ noBlocks:
afterBlocks:
ADDQ DX, AX
// Right now BX has len(b)-32, and we want to loop until CX > len(b)-8.
// Right now BX has len(b)-32, and we want to loop until SI > len(b)-8.
ADDQ $24, BX
CMPQ CX, BX
CMPQ SI, BX
JG fourByte
wordLoop:
// Calculate k1.
MOVQ (CX), R8
ADDQ $8, CX
MOVQ (SI), R8
ADDQ $8, SI
IMULQ R14, R8
ROLQ $31, R8
IMULQ R13, R8
@ -117,18 +117,18 @@ wordLoop:
XORQ R8, AX
ROLQ $27, AX
IMULQ R13, AX
ADDQ R15, AX
ADDQ DI, AX
CMPQ CX, BX
CMPQ SI, BX
JLE wordLoop
fourByte:
ADDQ $4, BX
CMPQ CX, BX
CMPQ SI, BX
JG singles
MOVL (CX), R8
ADDQ $4, CX
MOVL (SI), R8
ADDQ $4, SI
IMULQ R13, R8
XORQ R8, AX
@ -138,19 +138,19 @@ fourByte:
singles:
ADDQ $4, BX
CMPQ CX, BX
CMPQ SI, BX
JGE finalize
singlesLoop:
MOVBQZX (CX), R12
ADDQ $1, CX
MOVBQZX (SI), R12
ADDQ $1, SI
IMULQ ·prime5v(SB), R12
XORQ R12, AX
ROLQ $11, AX
IMULQ R13, AX
CMPQ CX, BX
CMPQ SI, BX
JL singlesLoop
finalize:
@ -179,9 +179,9 @@ TEXT ·writeBlocks(SB), NOSPLIT, $0-40
MOVQ ·prime2v(SB), R14
// Load slice.
MOVQ b_base+8(FP), CX
MOVQ b_base+8(FP), SI
MOVQ b_len+16(FP), DX
LEAQ (CX)(DX*1), BX
LEAQ (SI)(DX*1), BX
SUBQ $32, BX
// Load vN from d.
@ -199,7 +199,7 @@ blockLoop:
round(R10)
round(R11)
CMPQ CX, BX
CMPQ SI, BX
JLE blockLoop
// Copy vN back to d.
@ -208,8 +208,8 @@ blockLoop:
MOVQ R10, 16(AX)
MOVQ R11, 24(AX)
// The number of bytes written is CX minus the old base pointer.
SUBQ b_base+8(FP), CX
MOVQ CX, ret+32(FP)
// The number of bytes written is SI minus the old base pointer.
SUBQ b_base+8(FP), SI
MOVQ SI, ret+32(FP)
RET

View File

@ -6,41 +6,52 @@
package xxhash
import (
"reflect"
"unsafe"
)
// Notes:
//
// See https://groups.google.com/d/msg/golang-nuts/dcjzJy-bSpw/tcZYBzQqAQAJ
// for some discussion about these unsafe conversions.
//
// In the future it's possible that compiler optimizations will make these
// unsafe operations unnecessary: https://golang.org/issue/2205.
// XxxString functions unnecessary by realizing that calls such as
// Sum64([]byte(s)) don't need to copy s. See https://golang.org/issue/2205.
// If that happens, even if we keep these functions they can be replaced with
// the trivial safe code.
// NOTE: The usual way of doing an unsafe string-to-[]byte conversion is:
//
// Both of these wrapper functions still incur function call overhead since they
// will not be inlined. We could write Go/asm copies of Sum64 and Digest.Write
// for strings to squeeze out a bit more speed. Mid-stack inlining should
// eventually fix this.
// var b []byte
// bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
// bh.Data = (*reflect.StringHeader)(unsafe.Pointer(&s)).Data
// bh.Len = len(s)
// bh.Cap = len(s)
//
// Unfortunately, as of Go 1.15.3 the inliner's cost model assigns a high enough
// weight to this sequence of expressions that any function that uses it will
// not be inlined. Instead, the functions below use a different unsafe
// conversion designed to minimize the inliner weight and allow both to be
// inlined. There is also a test (TestInlining) which verifies that these are
// inlined.
//
// See https://github.com/golang/go/issues/42739 for discussion.
// Sum64String computes the 64-bit xxHash digest of s.
// It may be faster than Sum64([]byte(s)) by avoiding a copy.
func Sum64String(s string) uint64 {
var b []byte
bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
bh.Data = (*reflect.StringHeader)(unsafe.Pointer(&s)).Data
bh.Len = len(s)
bh.Cap = len(s)
b := *(*[]byte)(unsafe.Pointer(&sliceHeader{s, len(s)}))
return Sum64(b)
}
// WriteString adds more data to d. It always returns len(s), nil.
// It may be faster than Write([]byte(s)) by avoiding a copy.
func (d *Digest) WriteString(s string) (n int, err error) {
var b []byte
bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
bh.Data = (*reflect.StringHeader)(unsafe.Pointer(&s)).Data
bh.Len = len(s)
bh.Cap = len(s)
return d.Write(b)
d.Write(*(*[]byte)(unsafe.Pointer(&sliceHeader{s, len(s)})))
// d.Write always returns len(s), nil.
// Ignoring the return output and returning these fixed values buys a
// savings of 6 in the inliner's cost model.
return len(s), nil
}
// sliceHeader is similar to reflect.SliceHeader, but it assumes that the layout
// of the first two words is the same as the layout of a string.
type sliceHeader struct {
s string
cap int
}

View File

@ -1,7 +1,7 @@
# cgroups
[![Build Status](https://github.com/containerd/cgroups/workflows/CI/badge.svg)](https://github.com/containerd/cgroups/actions?query=workflow%3ACI)
[![codecov](https://codecov.io/gh/containerd/cgroups/branch/master/graph/badge.svg)](https://codecov.io/gh/containerd/cgroups)
[![codecov](https://codecov.io/gh/containerd/cgroups/branch/main/graph/badge.svg)](https://codecov.io/gh/containerd/cgroups)
[![GoDoc](https://godoc.org/github.com/containerd/cgroups?status.svg)](https://godoc.org/github.com/containerd/cgroups)
[![Go Report Card](https://goreportcard.com/badge/github.com/containerd/cgroups)](https://goreportcard.com/report/github.com/containerd/cgroups)
@ -26,7 +26,7 @@ uses the v1 implementation of cgroups.
```go
shares := uint64(100)
control, err := cgroups.New(cgroups.V1, cgroups.StaticPath("/test"), &specs.LinuxResources{
CPU: &specs.CPU{
CPU: &specs.LinuxCPU{
Shares: &shares,
},
})
@ -142,8 +142,8 @@ All static path should not include `/sys/fs/cgroup/` prefix, it should start wit
Cgroups is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE).
As a containerd sub-project, you will find the:
* [Project governance](https://github.com/containerd/project/blob/master/GOVERNANCE.md),
* [Maintainers](https://github.com/containerd/project/blob/master/MAINTAINERS),
* and [Contributing guidelines](https://github.com/containerd/project/blob/master/CONTRIBUTING.md)
* [Project governance](https://github.com/containerd/project/blob/main/GOVERNANCE.md),
* [Maintainers](https://github.com/containerd/project/blob/main/MAINTAINERS),
* and [Contributing guidelines](https://github.com/containerd/project/blob/main/CONTRIBUTING.md)
information in our [`containerd/project`](https://github.com/containerd/project) repository.

View File

@ -3,19 +3,19 @@
Vagrant.configure("2") do |config|
# Fedora box is used for testing cgroup v2 support
config.vm.box = "fedora/32-cloud-base"
config.vm.box = "fedora/35-cloud-base"
config.vm.provider :virtualbox do |v|
v.memory = 2048
v.memory = 4096
v.cpus = 2
end
config.vm.provider :libvirt do |v|
v.memory = 2048
v.memory = 4096
v.cpus = 2
end
config.vm.provision "shell", inline: <<-SHELL
set -eux -o pipefail
# configuration
GO_VERSION="1.15"
GO_VERSION="1.17.7"
# install gcc and Golang
dnf -y install gcc

View File

@ -130,7 +130,7 @@ func (b *blkioController) Stat(path string, stats *v1.Metrics) error {
}
}
f, err := os.Open(filepath.Join(b.procRoot, "diskstats"))
f, err := os.Open(filepath.Join(b.procRoot, "partitions"))
if err != nil {
return err
}
@ -335,7 +335,10 @@ func getDevices(r io.Reader) (map[deviceKey]string, error) {
s = bufio.NewScanner(r)
devices = make(map[deviceKey]string)
)
for s.Scan() {
for i := 0; s.Scan(); i++ {
if i < 2 {
continue
}
fields := strings.Fields(s.Text())
major, err := strconv.Atoi(fields[0])
if err != nil {
@ -352,7 +355,7 @@ func getDevices(r io.Reader) (map[deviceKey]string, error) {
if _, ok := devices[key]; ok {
continue
}
devices[key] = filepath.Join("/dev", fields[2])
devices[key] = filepath.Join("/dev", fields[3])
}
return devices, s.Err()
}

View File

@ -17,6 +17,7 @@
package cgroups
import (
"errors"
"fmt"
"os"
"path/filepath"
@ -25,8 +26,8 @@ import (
"sync"
v1 "github.com/containerd/cgroups/stats/v1"
specs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
"github.com/opencontainers/runtime-spec/specs-go"
)
// New returns a new control via the cgroup cgroups interface
@ -83,7 +84,7 @@ func Load(hierarchy Hierarchy, path Path, opts ...InitOpts) (Cgroup, error) {
for _, s := range pathers(subsystems) {
p, err := path(s.Name())
if err != nil {
if os.IsNotExist(errors.Cause(err)) {
if errors.Is(err, os.ErrNotExist) {
return nil, ErrCgroupDeleted
}
if err == ErrControllerNotActive {
@ -149,8 +150,50 @@ func (c *cgroup) Subsystems() []Subsystem {
return c.subsystems
}
// Add moves the provided process into the new cgroup
func (c *cgroup) Add(process Process) error {
func (c *cgroup) subsystemsFilter(subsystems ...Name) []Subsystem {
if len(subsystems) == 0 {
return c.subsystems
}
var filteredSubsystems = []Subsystem{}
for _, s := range c.subsystems {
for _, f := range subsystems {
if s.Name() == f {
filteredSubsystems = append(filteredSubsystems, s)
break
}
}
}
return filteredSubsystems
}
// Add moves the provided process into the new cgroup.
// Without additional arguments, the process is added to all the cgroup subsystems.
// When giving Add a list of subsystem names, the process is only added to those
// subsystems, provided that they are active in the targeted cgroup.
func (c *cgroup) Add(process Process, subsystems ...Name) error {
return c.add(process, cgroupProcs, subsystems...)
}
// AddProc moves the provided process id into the new cgroup.
// Without additional arguments, the process with the given id is added to all
// the cgroup subsystems. When giving AddProc a list of subsystem names, the process
// id is only added to those subsystems, provided that they are active in the targeted
// cgroup.
func (c *cgroup) AddProc(pid uint64, subsystems ...Name) error {
return c.add(Process{Pid: int(pid)}, cgroupProcs, subsystems...)
}
// AddTask moves the provided tasks (threads) into the new cgroup.
// Without additional arguments, the task is added to all the cgroup subsystems.
// When giving AddTask a list of subsystem names, the task is only added to those
// subsystems, provided that they are active in the targeted cgroup.
func (c *cgroup) AddTask(process Process, subsystems ...Name) error {
return c.add(process, cgroupTasks, subsystems...)
}
func (c *cgroup) add(process Process, pType procType, subsystems ...Name) error {
if process.Pid <= 0 {
return ErrInvalidPid
}
@ -159,52 +202,19 @@ func (c *cgroup) Add(process Process) error {
if c.err != nil {
return c.err
}
return c.add(process)
}
func (c *cgroup) add(process Process) error {
for _, s := range pathers(c.subsystems) {
for _, s := range pathers(c.subsystemsFilter(subsystems...)) {
p, err := c.path(s.Name())
if err != nil {
return err
}
if err := retryingWriteFile(
filepath.Join(s.Path(p), cgroupProcs),
err = retryingWriteFile(
filepath.Join(s.Path(p), pType),
[]byte(strconv.Itoa(process.Pid)),
defaultFilePerm,
); err != nil {
return err
}
}
return nil
}
// AddTask moves the provided tasks (threads) into the new cgroup
func (c *cgroup) AddTask(process Process) error {
if process.Pid <= 0 {
return ErrInvalidPid
}
c.mu.Lock()
defer c.mu.Unlock()
if c.err != nil {
return c.err
}
return c.addTask(process)
}
func (c *cgroup) addTask(process Process) error {
for _, s := range pathers(c.subsystems) {
p, err := c.path(s.Name())
)
if err != nil {
return err
}
if err := retryingWriteFile(
filepath.Join(s.Path(p), cgroupTasks),
[]byte(strconv.Itoa(process.Pid)),
defaultFilePerm,
); err != nil {
return err
}
}
return nil
}
@ -326,15 +336,29 @@ func (c *cgroup) Processes(subsystem Name, recursive bool) ([]Process, error) {
if c.err != nil {
return nil, c.err
}
return c.processes(subsystem, recursive)
return c.processes(subsystem, recursive, cgroupProcs)
}
func (c *cgroup) processes(subsystem Name, recursive bool) ([]Process, error) {
// Tasks returns the tasks running inside the cgroup along
// with the subsystem used, pid, and path
func (c *cgroup) Tasks(subsystem Name, recursive bool) ([]Task, error) {
c.mu.Lock()
defer c.mu.Unlock()
if c.err != nil {
return nil, c.err
}
return c.processes(subsystem, recursive, cgroupTasks)
}
func (c *cgroup) processes(subsystem Name, recursive bool, pType procType) ([]Process, error) {
s := c.getSubsystem(subsystem)
sp, err := c.path(subsystem)
if err != nil {
return nil, err
}
if s == nil {
return nil, fmt.Errorf("cgroups: %s doesn't exist in %s subsystem", sp, subsystem)
}
path := s.(pather).Path(sp)
var processes []Process
err = filepath.Walk(path, func(p string, info os.FileInfo, err error) error {
@ -348,10 +372,10 @@ func (c *cgroup) processes(subsystem Name, recursive bool) ([]Process, error) {
return filepath.SkipDir
}
dir, name := filepath.Split(p)
if name != cgroupProcs {
if name != pType {
return nil
}
procs, err := readPids(dir, subsystem)
procs, err := readPids(dir, subsystem, pType)
if err != nil {
return err
}
@ -361,49 +385,6 @@ func (c *cgroup) processes(subsystem Name, recursive bool) ([]Process, error) {
return processes, err
}
// Tasks returns the tasks running inside the cgroup along
// with the subsystem used, pid, and path
func (c *cgroup) Tasks(subsystem Name, recursive bool) ([]Task, error) {
c.mu.Lock()
defer c.mu.Unlock()
if c.err != nil {
return nil, c.err
}
return c.tasks(subsystem, recursive)
}
func (c *cgroup) tasks(subsystem Name, recursive bool) ([]Task, error) {
s := c.getSubsystem(subsystem)
sp, err := c.path(subsystem)
if err != nil {
return nil, err
}
path := s.(pather).Path(sp)
var tasks []Task
err = filepath.Walk(path, func(p string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !recursive && info.IsDir() {
if p == path {
return nil
}
return filepath.SkipDir
}
dir, name := filepath.Split(p)
if name != cgroupTasks {
return nil
}
procs, err := readTasksPids(dir, subsystem)
if err != nil {
return err
}
tasks = append(tasks, procs...)
return nil
})
return tasks, err
}
// Freeze freezes the entire cgroup and all the processes inside it
func (c *cgroup) Freeze() error {
c.mu.Lock()
@ -511,7 +492,7 @@ func (c *cgroup) MoveTo(destination Cgroup) error {
return c.err
}
for _, s := range c.subsystems {
processes, err := c.processes(s.Name(), true)
processes, err := c.processes(s.Name(), true, cgroupProcs)
if err != nil {
return err
}

View File

@ -23,10 +23,12 @@ import (
specs "github.com/opencontainers/runtime-spec/specs-go"
)
type procType = string
const (
cgroupProcs = "cgroup.procs"
cgroupTasks = "tasks"
defaultDirPerm = 0755
cgroupProcs procType = "cgroup.procs"
cgroupTasks procType = "tasks"
defaultDirPerm = 0755
)
// defaultFilePerm is a var so that the test framework can change the filemode
@ -37,32 +39,37 @@ const (
var defaultFilePerm = os.FileMode(0)
type Process struct {
// Subsystem is the name of the subsystem that the process is in
// Subsystem is the name of the subsystem that the process / task is in.
Subsystem Name
// Pid is the process id of the process
// Pid is the process id of the process / task.
Pid int
// Path is the full path of the subsystem and location that the process is in
// Path is the full path of the subsystem and location that the process / task is in.
Path string
}
type Task struct {
// Subsystem is the name of the subsystem that the task is in
Subsystem Name
// Pid is the process id of the task
Pid int
// Path is the full path of the subsystem and location that the task is in
Path string
}
type Task = Process
// Cgroup handles interactions with the individual groups to perform
// actions on them as them main interface to this cgroup package
type Cgroup interface {
// New creates a new cgroup under the calling cgroup
New(string, *specs.LinuxResources) (Cgroup, error)
// Add adds a process to the cgroup (cgroup.procs)
Add(Process) error
// AddTask adds a process to the cgroup (tasks)
AddTask(Process) error
// Add adds a process to the cgroup (cgroup.procs). Without additional arguments,
// the process is added to all the cgroup subsystems. When giving Add a list of
// subsystem names, the process is only added to those subsystems, provided that
// they are active in the targeted cgroup.
Add(Process, ...Name) error
// AddProc adds the process with the given id to the cgroup (cgroup.procs).
// Without additional arguments, the process with the given id is added to all
// the cgroup subsystems. When giving AddProc a list of subsystem names, the process
// id is only added to those subsystems, provided that they are active in the targeted
// cgroup.
AddProc(uint64, ...Name) error
// AddTask adds a process to the cgroup (tasks). Without additional arguments, the
// task is added to all the cgroup subsystems. When giving AddTask a list of subsystem
// names, the task is only added to those subsystems, provided that they are active in
// the targeted cgroup.
AddTask(Process, ...Name) error
// Delete removes the cgroup as a whole
Delete() error
// MoveTo moves all the processes under the calling cgroup to the provided one

View File

@ -17,7 +17,7 @@
package cgroups
import (
"github.com/pkg/errors"
"errors"
)
var (

View File

@ -17,10 +17,9 @@
package cgroups
import (
"errors"
"fmt"
"path/filepath"
"github.com/pkg/errors"
)
type Path func(subsystem Name) (string, error)
@ -39,7 +38,7 @@ func StaticPath(path string) Path {
// NestedPath will nest the cgroups based on the calling processes cgroup
// placing its child processes inside its own path
func NestedPath(suffix string) Path {
paths, err := parseCgroupFile("/proc/self/cgroup")
paths, err := ParseCgroupFile("/proc/self/cgroup")
if err != nil {
return errorPath(err)
}
@ -50,9 +49,9 @@ func NestedPath(suffix string) Path {
// This is commonly used for the Load function to restore an existing container
func PidPath(pid int) Path {
p := fmt.Sprintf("/proc/%d/cgroup", pid)
paths, err := parseCgroupFile(p)
paths, err := ParseCgroupFile(p)
if err != nil {
return errorPath(errors.Wrapf(err, "parse cgroup file %s", p))
return errorPath(fmt.Errorf("parse cgroup file %s: %w", p, err))
}
return existingPath(paths, "")
}

View File

@ -67,6 +67,7 @@ func (p *rdmaController) Create(path string, resources *specs.LinuxResources) er
for device, limit := range resources.Rdma {
if device != "" && (limit.HcaHandles != nil || limit.HcaObjects != nil) {
limit := limit
return retryingWriteFile(
filepath.Join(p.Path(path), "rdma.max"),
[]byte(createCmdString(device, &limit)),

File diff suppressed because it is too large Load Diff

View File

@ -517,21 +517,21 @@ file {
number: 1
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "oom_kill_disable"
json_name: "oomKillDisable"
}
field {
name: "under_oom"
number: 2
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "under_oom"
json_name: "underOom"
}
field {
name: "oom_kill"
number: 3
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "oom_kill"
json_name: "oomKill"
}
}
message_type {

View File

@ -18,6 +18,7 @@ package cgroups
import (
"fmt"
"os"
v1 "github.com/containerd/cgroups/stats/v1"
specs "github.com/opencontainers/runtime-spec/specs-go"
@ -46,7 +47,6 @@ const (
// available on most linux systems
func Subsystems() []Name {
n := []Name{
Hugetlb,
Freezer,
Pids,
NetCLS,
@ -62,6 +62,9 @@ func Subsystems() []Name {
if !RunningInUserNS() {
n = append(n, Devices)
}
if _, err := os.Stat("/sys/kernel/mm/hugepages"); err == nil {
n = append(n, Hugetlb)
}
return n
}

View File

@ -17,6 +17,7 @@
package cgroups
import (
"context"
"path/filepath"
"strings"
"sync"
@ -78,7 +79,8 @@ func (s *SystemdController) Name() Name {
}
func (s *SystemdController) Create(path string, _ *specs.LinuxResources) error {
conn, err := systemdDbus.New()
ctx := context.TODO()
conn, err := systemdDbus.NewWithContext(ctx)
if err != nil {
return err
}
@ -90,7 +92,7 @@ func (s *SystemdController) Create(path string, _ *specs.LinuxResources) error {
checkDelegate := func() {
canDelegate = true
dlSlice := newProperty("Delegate", true)
if _, err := conn.StartTransientUnit(slice, "testdelegate", []systemdDbus.Property{dlSlice}, nil); err != nil {
if _, err := conn.StartTransientUnitContext(ctx, slice, "testdelegate", []systemdDbus.Property{dlSlice}, nil); err != nil {
if dbusError, ok := err.(dbus.Error); ok {
// Starting with systemd v237, Delegate is not even a property of slices anymore,
// so the D-Bus call fails with "InvalidArgs" error.
@ -100,7 +102,7 @@ func (s *SystemdController) Create(path string, _ *specs.LinuxResources) error {
}
}
conn.StopUnit(slice, "testDelegate", nil)
_, _ = conn.StopUnitContext(ctx, slice, "testDelegate", nil)
}
once.Do(checkDelegate)
properties := []systemdDbus.Property{
@ -118,7 +120,7 @@ func (s *SystemdController) Create(path string, _ *specs.LinuxResources) error {
}
ch := make(chan string)
_, err = conn.StartTransientUnit(name, "replace", properties, ch)
_, err = conn.StartTransientUnitContext(ctx, name, "replace", properties, ch)
if err != nil {
return err
}
@ -127,14 +129,15 @@ func (s *SystemdController) Create(path string, _ *specs.LinuxResources) error {
}
func (s *SystemdController) Delete(path string) error {
conn, err := systemdDbus.New()
ctx := context.TODO()
conn, err := systemdDbus.NewWithContext(ctx)
if err != nil {
return err
}
defer conn.Close()
_, name := splitName(path)
ch := make(chan string)
_, err = conn.StopUnit(name, "replace", ch)
_, err = conn.StopUnitContext(ctx, name, "replace", ch)
if err != nil {
return err
}

View File

@ -164,9 +164,9 @@ func remove(path string) error {
return fmt.Errorf("cgroups: unable to remove path %q", path)
}
// readPids will read all the pids of processes in a cgroup by the provided path
func readPids(path string, subsystem Name) ([]Process, error) {
f, err := os.Open(filepath.Join(path, cgroupProcs))
// readPids will read all the pids of processes or tasks in a cgroup by the provided path
func readPids(path string, subsystem Name, pType procType) ([]Process, error) {
f, err := os.Open(filepath.Join(path, pType))
if err != nil {
return nil, err
}
@ -195,36 +195,6 @@ func readPids(path string, subsystem Name) ([]Process, error) {
return out, nil
}
// readTasksPids will read all the pids of tasks in a cgroup by the provided path
func readTasksPids(path string, subsystem Name) ([]Task, error) {
f, err := os.Open(filepath.Join(path, cgroupTasks))
if err != nil {
return nil, err
}
defer f.Close()
var (
out []Task
s = bufio.NewScanner(f)
)
for s.Scan() {
if t := s.Text(); t != "" {
pid, err := strconv.Atoi(t)
if err != nil {
return nil, err
}
out = append(out, Task{
Pid: pid,
Subsystem: subsystem,
Path: path,
})
}
}
if err := s.Err(); err != nil {
return nil, err
}
return out, nil
}
func hugePageSizes() ([]string, error) {
var (
pageSizes []string
@ -285,18 +255,34 @@ func parseKV(raw string) (string, uint64, error) {
}
}
func parseCgroupFile(path string) (map[string]string, error) {
f, err := os.Open(path)
if err != nil {
return nil, err
}
defer f.Close()
return parseCgroupFromReader(f)
// ParseCgroupFile parses the given cgroup file, typically /proc/self/cgroup
// or /proc/<pid>/cgroup, into a map of subsystems to cgroup paths, e.g.
// "cpu": "/user.slice/user-1000.slice"
// "pids": "/user.slice/user-1000.slice"
// etc.
//
// The resulting map does not have an element for cgroup v2 unified hierarchy.
// Use ParseCgroupFileUnified to get the unified path.
func ParseCgroupFile(path string) (map[string]string, error) {
x, _, err := ParseCgroupFileUnified(path)
return x, err
}
func parseCgroupFromReader(r io.Reader) (map[string]string, error) {
// ParseCgroupFileUnified returns legacy subsystem paths as the first value,
// and returns the unified path as the second value.
func ParseCgroupFileUnified(path string) (map[string]string, string, error) {
f, err := os.Open(path)
if err != nil {
return nil, "", err
}
defer f.Close()
return parseCgroupFromReaderUnified(f)
}
func parseCgroupFromReaderUnified(r io.Reader) (map[string]string, string, error) {
var (
cgroups = make(map[string]string)
unified = ""
s = bufio.NewScanner(r)
)
for s.Scan() {
@ -305,18 +291,20 @@ func parseCgroupFromReader(r io.Reader) (map[string]string, error) {
parts = strings.SplitN(text, ":", 3)
)
if len(parts) < 3 {
return nil, fmt.Errorf("invalid cgroup entry: %q", text)
return nil, unified, fmt.Errorf("invalid cgroup entry: %q", text)
}
for _, subs := range strings.Split(parts[1], ",") {
if subs != "" {
if subs == "" {
unified = parts[2]
} else {
cgroups[subs] = parts[2]
}
}
}
if err := s.Err(); err != nil {
return nil, err
return nil, unified, err
}
return cgroups, nil
return cgroups, unified, nil
}
func getCgroupDestination(subsystem string) (string, error) {

View File

@ -16,6 +16,7 @@
package dbus
import (
"context"
"encoding/hex"
"fmt"
"os"
@ -110,46 +111,66 @@ type Conn struct {
}
}
// New establishes a connection to any available bus and authenticates.
// Callers should call Close() when done with the connection.
// Deprecated: use NewWithContext instead.
func New() (*Conn, error) {
conn, err := NewSystemConnection()
return NewWithContext(context.Background())
}
// NewWithContext establishes a connection to any available bus and authenticates.
// Callers should call Close() when done with the connection.
func NewWithContext(ctx context.Context) (*Conn, error) {
conn, err := NewSystemConnectionContext(ctx)
if err != nil && os.Geteuid() == 0 {
return NewSystemdConnection()
return NewSystemdConnectionContext(ctx)
}
return conn, err
}
// NewSystemConnection establishes a connection to the system bus and authenticates.
// Callers should call Close() when done with the connection
// Deprecated: use NewSystemConnectionContext instead.
func NewSystemConnection() (*Conn, error) {
return NewSystemConnectionContext(context.Background())
}
// NewSystemConnectionContext establishes a connection to the system bus and authenticates.
// Callers should call Close() when done with the connection.
func NewSystemConnectionContext(ctx context.Context) (*Conn, error) {
return NewConnection(func() (*dbus.Conn, error) {
return dbusAuthHelloConnection(dbus.SystemBusPrivate)
return dbusAuthHelloConnection(ctx, dbus.SystemBusPrivate)
})
}
// NewUserConnection establishes a connection to the session bus and
// Deprecated: use NewUserConnectionContext instead.
func NewUserConnection() (*Conn, error) {
return NewUserConnectionContext(context.Background())
}
// NewUserConnectionContext establishes a connection to the session bus and
// authenticates. This can be used to connect to systemd user instances.
// Callers should call Close() when done with the connection.
func NewUserConnection() (*Conn, error) {
func NewUserConnectionContext(ctx context.Context) (*Conn, error) {
return NewConnection(func() (*dbus.Conn, error) {
return dbusAuthHelloConnection(dbus.SessionBusPrivate)
return dbusAuthHelloConnection(ctx, dbus.SessionBusPrivate)
})
}
// NewSystemdConnection establishes a private, direct connection to systemd.
// Deprecated: use NewSystemdConnectionContext instead.
func NewSystemdConnection() (*Conn, error) {
return NewSystemdConnectionContext(context.Background())
}
// NewSystemdConnectionContext establishes a private, direct connection to systemd.
// This can be used for communicating with systemd without a dbus daemon.
// Callers should call Close() when done with the connection.
func NewSystemdConnection() (*Conn, error) {
func NewSystemdConnectionContext(ctx context.Context) (*Conn, error) {
return NewConnection(func() (*dbus.Conn, error) {
// We skip Hello when talking directly to systemd.
return dbusAuthConnection(func(opts ...dbus.ConnOption) (*dbus.Conn, error) {
return dbus.Dial("unix:path=/run/systemd/private")
return dbusAuthConnection(ctx, func(opts ...dbus.ConnOption) (*dbus.Conn, error) {
return dbus.Dial("unix:path=/run/systemd/private", opts...)
})
})
}
// Close closes an established connection
// Close closes an established connection.
func (c *Conn) Close() {
c.sysconn.Close()
c.sigconn.Close()
@ -192,7 +213,7 @@ func NewConnection(dialBus func() (*dbus.Conn, error)) (*Conn, error) {
// GetManagerProperty returns the value of a property on the org.freedesktop.systemd1.Manager
// interface. The value is returned in its string representation, as defined at
// https://developer.gnome.org/glib/unstable/gvariant-text.html
// https://developer.gnome.org/glib/unstable/gvariant-text.html.
func (c *Conn) GetManagerProperty(prop string) (string, error) {
variant, err := c.sysobj.GetProperty("org.freedesktop.systemd1.Manager." + prop)
if err != nil {
@ -201,8 +222,8 @@ func (c *Conn) GetManagerProperty(prop string) (string, error) {
return variant.String(), nil
}
func dbusAuthConnection(createBus func(opts ...dbus.ConnOption) (*dbus.Conn, error)) (*dbus.Conn, error) {
conn, err := createBus()
func dbusAuthConnection(ctx context.Context, createBus func(opts ...dbus.ConnOption) (*dbus.Conn, error)) (*dbus.Conn, error) {
conn, err := createBus(dbus.WithContext(ctx))
if err != nil {
return nil, err
}
@ -221,8 +242,8 @@ func dbusAuthConnection(createBus func(opts ...dbus.ConnOption) (*dbus.Conn, err
return conn, nil
}
func dbusAuthHelloConnection(createBus func(opts ...dbus.ConnOption) (*dbus.Conn, error)) (*dbus.Conn, error) {
conn, err := dbusAuthConnection(createBus)
func dbusAuthHelloConnection(ctx context.Context, createBus func(opts ...dbus.ConnOption) (*dbus.Conn, error)) (*dbus.Conn, error) {
conn, err := dbusAuthConnection(ctx, createBus)
if err != nil {
return nil, err
}

View File

@ -15,6 +15,7 @@
package dbus
import (
"context"
"errors"
"fmt"
"path"
@ -23,6 +24,18 @@ import (
"github.com/godbus/dbus/v5"
)
// Who can be used to specify which process to kill in the unit via the KillUnitWithTarget API
type Who string
const (
// All sends the signal to all processes in the unit
All Who = "all"
// Main sends the signal to the main process of the unit
Main Who = "main"
// Control sends the signal to the control process of the unit
Control Who = "control"
)
func (c *Conn) jobComplete(signal *dbus.Signal) {
var id uint32
var job dbus.ObjectPath
@ -38,14 +51,14 @@ func (c *Conn) jobComplete(signal *dbus.Signal) {
c.jobListener.Unlock()
}
func (c *Conn) startJob(ch chan<- string, job string, args ...interface{}) (int, error) {
func (c *Conn) startJob(ctx context.Context, ch chan<- string, job string, args ...interface{}) (int, error) {
if ch != nil {
c.jobListener.Lock()
defer c.jobListener.Unlock()
}
var p dbus.ObjectPath
err := c.sysobj.Call(job, 0, args...).Store(&p)
err := c.sysobj.CallWithContext(ctx, job, 0, args...).Store(&p)
if err != nil {
return 0, err
}
@ -60,7 +73,12 @@ func (c *Conn) startJob(ch chan<- string, job string, args ...interface{}) (int,
return jobID, nil
}
// StartUnit enqueues a start job and depending jobs, if any (unless otherwise
// Deprecated: use StartUnitContext instead.
func (c *Conn) StartUnit(name string, mode string, ch chan<- string) (int, error) {
return c.StartUnitContext(context.Background(), name, mode, ch)
}
// StartUnitContext enqueues a start job and depending jobs, if any (unless otherwise
// specified by the mode string).
//
// Takes the unit to activate, plus a mode string. The mode needs to be one of
@ -90,72 +108,130 @@ func (c *Conn) startJob(ch chan<- string, job string, args ...interface{}) (int,
// should not be considered authoritative.
//
// If an error does occur, it will be returned to the user alongside a job ID of 0.
func (c *Conn) StartUnit(name string, mode string, ch chan<- string) (int, error) {
return c.startJob(ch, "org.freedesktop.systemd1.Manager.StartUnit", name, mode)
func (c *Conn) StartUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) {
return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.StartUnit", name, mode)
}
// StopUnit is similar to StartUnit but stops the specified unit rather
// than starting it.
// Deprecated: use StopUnitContext instead.
func (c *Conn) StopUnit(name string, mode string, ch chan<- string) (int, error) {
return c.startJob(ch, "org.freedesktop.systemd1.Manager.StopUnit", name, mode)
return c.StopUnitContext(context.Background(), name, mode, ch)
}
// ReloadUnit reloads a unit. Reloading is done only if the unit is already running and fails otherwise.
// StopUnitContext is similar to StartUnitContext, but stops the specified unit
// rather than starting it.
func (c *Conn) StopUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) {
return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.StopUnit", name, mode)
}
// Deprecated: use ReloadUnitContext instead.
func (c *Conn) ReloadUnit(name string, mode string, ch chan<- string) (int, error) {
return c.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadUnit", name, mode)
return c.ReloadUnitContext(context.Background(), name, mode, ch)
}
// RestartUnit restarts a service. If a service is restarted that isn't
// running it will be started.
// ReloadUnitContext reloads a unit. Reloading is done only if the unit
// is already running, and fails otherwise.
func (c *Conn) ReloadUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) {
return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.ReloadUnit", name, mode)
}
// Deprecated: use RestartUnitContext instead.
func (c *Conn) RestartUnit(name string, mode string, ch chan<- string) (int, error) {
return c.startJob(ch, "org.freedesktop.systemd1.Manager.RestartUnit", name, mode)
return c.RestartUnitContext(context.Background(), name, mode, ch)
}
// TryRestartUnit is like RestartUnit, except that a service that isn't running
// is not affected by the restart.
// RestartUnitContext restarts a service. If a service is restarted that isn't
// running it will be started.
func (c *Conn) RestartUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) {
return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.RestartUnit", name, mode)
}
// Deprecated: use TryRestartUnitContext instead.
func (c *Conn) TryRestartUnit(name string, mode string, ch chan<- string) (int, error) {
return c.startJob(ch, "org.freedesktop.systemd1.Manager.TryRestartUnit", name, mode)
return c.TryRestartUnitContext(context.Background(), name, mode, ch)
}
// ReloadOrRestartUnit attempts a reload if the unit supports it and use a restart
// otherwise.
// TryRestartUnitContext is like RestartUnitContext, except that a service that
// isn't running is not affected by the restart.
func (c *Conn) TryRestartUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) {
return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.TryRestartUnit", name, mode)
}
// Deprecated: use ReloadOrRestartUnitContext instead.
func (c *Conn) ReloadOrRestartUnit(name string, mode string, ch chan<- string) (int, error) {
return c.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadOrRestartUnit", name, mode)
return c.ReloadOrRestartUnitContext(context.Background(), name, mode, ch)
}
// ReloadOrTryRestartUnit attempts a reload if the unit supports it and use a "Try"
// flavored restart otherwise.
// ReloadOrRestartUnitContext attempts a reload if the unit supports it and use
// a restart otherwise.
func (c *Conn) ReloadOrRestartUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) {
return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.ReloadOrRestartUnit", name, mode)
}
// Deprecated: use ReloadOrTryRestartUnitContext instead.
func (c *Conn) ReloadOrTryRestartUnit(name string, mode string, ch chan<- string) (int, error) {
return c.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadOrTryRestartUnit", name, mode)
return c.ReloadOrTryRestartUnitContext(context.Background(), name, mode, ch)
}
// StartTransientUnit() may be used to create and start a transient unit, which
// ReloadOrTryRestartUnitContext attempts a reload if the unit supports it,
// and use a "Try" flavored restart otherwise.
func (c *Conn) ReloadOrTryRestartUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) {
return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.ReloadOrTryRestartUnit", name, mode)
}
// Deprecated: use StartTransientUnitContext instead.
func (c *Conn) StartTransientUnit(name string, mode string, properties []Property, ch chan<- string) (int, error) {
return c.StartTransientUnitContext(context.Background(), name, mode, properties, ch)
}
// StartTransientUnitContext may be used to create and start a transient unit, which
// will be released as soon as it is not running or referenced anymore or the
// system is rebooted. name is the unit name including suffix, and must be
// unique. mode is the same as in StartUnit(), properties contains properties
// unique. mode is the same as in StartUnitContext, properties contains properties
// of the unit.
func (c *Conn) StartTransientUnit(name string, mode string, properties []Property, ch chan<- string) (int, error) {
return c.startJob(ch, "org.freedesktop.systemd1.Manager.StartTransientUnit", name, mode, properties, make([]PropertyCollection, 0))
func (c *Conn) StartTransientUnitContext(ctx context.Context, name string, mode string, properties []Property, ch chan<- string) (int, error) {
return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.StartTransientUnit", name, mode, properties, make([]PropertyCollection, 0))
}
// KillUnit takes the unit name and a UNIX signal number to send. All of the unit's
// processes are killed.
// Deprecated: use KillUnitContext instead.
func (c *Conn) KillUnit(name string, signal int32) {
c.sysobj.Call("org.freedesktop.systemd1.Manager.KillUnit", 0, name, "all", signal).Store()
c.KillUnitContext(context.Background(), name, signal)
}
// ResetFailedUnit resets the "failed" state of a specific unit.
// KillUnitContext takes the unit name and a UNIX signal number to send.
// All of the unit's processes are killed.
func (c *Conn) KillUnitContext(ctx context.Context, name string, signal int32) {
c.KillUnitWithTarget(ctx, name, All, signal)
}
// KillUnitWithTarget is like KillUnitContext, but allows you to specify which
// process in the unit to send the signal to.
func (c *Conn) KillUnitWithTarget(ctx context.Context, name string, target Who, signal int32) error {
return c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.KillUnit", 0, name, string(target), signal).Store()
}
// Deprecated: use ResetFailedUnitContext instead.
func (c *Conn) ResetFailedUnit(name string) error {
return c.sysobj.Call("org.freedesktop.systemd1.Manager.ResetFailedUnit", 0, name).Store()
return c.ResetFailedUnitContext(context.Background(), name)
}
// SystemState returns the systemd state. Equivalent to `systemctl is-system-running`.
// ResetFailedUnitContext resets the "failed" state of a specific unit.
func (c *Conn) ResetFailedUnitContext(ctx context.Context, name string) error {
return c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ResetFailedUnit", 0, name).Store()
}
// Deprecated: use SystemStateContext instead.
func (c *Conn) SystemState() (*Property, error) {
return c.SystemStateContext(context.Background())
}
// SystemStateContext returns the systemd state. Equivalent to
// systemctl is-system-running.
func (c *Conn) SystemStateContext(ctx context.Context) (*Property, error) {
var err error
var prop dbus.Variant
obj := c.sysconn.Object("org.freedesktop.systemd1", "/org/freedesktop/systemd1")
err = obj.Call("org.freedesktop.DBus.Properties.Get", 0, "org.freedesktop.systemd1.Manager", "SystemState").Store(&prop)
err = obj.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, "org.freedesktop.systemd1.Manager", "SystemState").Store(&prop)
if err != nil {
return nil, err
}
@ -163,8 +239,8 @@ func (c *Conn) SystemState() (*Property, error) {
return &Property{Name: "SystemState", Value: prop}, nil
}
// getProperties takes the unit path and returns all of its dbus object properties, for the given dbus interface
func (c *Conn) getProperties(path dbus.ObjectPath, dbusInterface string) (map[string]interface{}, error) {
// getProperties takes the unit path and returns all of its dbus object properties, for the given dbus interface.
func (c *Conn) getProperties(ctx context.Context, path dbus.ObjectPath, dbusInterface string) (map[string]interface{}, error) {
var err error
var props map[string]dbus.Variant
@ -173,7 +249,7 @@ func (c *Conn) getProperties(path dbus.ObjectPath, dbusInterface string) (map[st
}
obj := c.sysconn.Object("org.freedesktop.systemd1", path)
err = obj.Call("org.freedesktop.DBus.Properties.GetAll", 0, dbusInterface).Store(&props)
err = obj.CallWithContext(ctx, "org.freedesktop.DBus.Properties.GetAll", 0, dbusInterface).Store(&props)
if err != nil {
return nil, err
}
@ -186,24 +262,42 @@ func (c *Conn) getProperties(path dbus.ObjectPath, dbusInterface string) (map[st
return out, nil
}
// GetUnitProperties takes the (unescaped) unit name and returns all of its dbus object properties.
// Deprecated: use GetUnitPropertiesContext instead.
func (c *Conn) GetUnitProperties(unit string) (map[string]interface{}, error) {
path := unitPath(unit)
return c.getProperties(path, "org.freedesktop.systemd1.Unit")
return c.GetUnitPropertiesContext(context.Background(), unit)
}
// GetUnitPathProperties takes the (escaped) unit path and returns all of its dbus object properties.
// GetUnitPropertiesContext takes the (unescaped) unit name and returns all of
// its dbus object properties.
func (c *Conn) GetUnitPropertiesContext(ctx context.Context, unit string) (map[string]interface{}, error) {
path := unitPath(unit)
return c.getProperties(ctx, path, "org.freedesktop.systemd1.Unit")
}
// Deprecated: use GetUnitPathPropertiesContext instead.
func (c *Conn) GetUnitPathProperties(path dbus.ObjectPath) (map[string]interface{}, error) {
return c.getProperties(path, "org.freedesktop.systemd1.Unit")
return c.GetUnitPathPropertiesContext(context.Background(), path)
}
// GetAllProperties takes the (unescaped) unit name and returns all of its dbus object properties.
// GetUnitPathPropertiesContext takes the (escaped) unit path and returns all
// of its dbus object properties.
func (c *Conn) GetUnitPathPropertiesContext(ctx context.Context, path dbus.ObjectPath) (map[string]interface{}, error) {
return c.getProperties(ctx, path, "org.freedesktop.systemd1.Unit")
}
// Deprecated: use GetAllPropertiesContext instead.
func (c *Conn) GetAllProperties(unit string) (map[string]interface{}, error) {
path := unitPath(unit)
return c.getProperties(path, "")
return c.GetAllPropertiesContext(context.Background(), unit)
}
func (c *Conn) getProperty(unit string, dbusInterface string, propertyName string) (*Property, error) {
// GetAllPropertiesContext takes the (unescaped) unit name and returns all of
// its dbus object properties.
func (c *Conn) GetAllPropertiesContext(ctx context.Context, unit string) (map[string]interface{}, error) {
path := unitPath(unit)
return c.getProperties(ctx, path, "")
}
func (c *Conn) getProperty(ctx context.Context, unit string, dbusInterface string, propertyName string) (*Property, error) {
var err error
var prop dbus.Variant
@ -213,7 +307,7 @@ func (c *Conn) getProperty(unit string, dbusInterface string, propertyName strin
}
obj := c.sysconn.Object("org.freedesktop.systemd1", path)
err = obj.Call("org.freedesktop.DBus.Properties.Get", 0, dbusInterface, propertyName).Store(&prop)
err = obj.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, dbusInterface, propertyName).Store(&prop)
if err != nil {
return nil, err
}
@ -221,36 +315,65 @@ func (c *Conn) getProperty(unit string, dbusInterface string, propertyName strin
return &Property{Name: propertyName, Value: prop}, nil
}
// Deprecated: use GetUnitPropertyContext instead.
func (c *Conn) GetUnitProperty(unit string, propertyName string) (*Property, error) {
return c.getProperty(unit, "org.freedesktop.systemd1.Unit", propertyName)
return c.GetUnitPropertyContext(context.Background(), unit, propertyName)
}
// GetServiceProperty returns property for given service name and property name
// GetUnitPropertyContext takes an (unescaped) unit name, and a property name,
// and returns the property value.
func (c *Conn) GetUnitPropertyContext(ctx context.Context, unit string, propertyName string) (*Property, error) {
return c.getProperty(ctx, unit, "org.freedesktop.systemd1.Unit", propertyName)
}
// Deprecated: use GetServicePropertyContext instead.
func (c *Conn) GetServiceProperty(service string, propertyName string) (*Property, error) {
return c.getProperty(service, "org.freedesktop.systemd1.Service", propertyName)
return c.GetServicePropertyContext(context.Background(), service, propertyName)
}
// GetUnitTypeProperties returns the extra properties for a unit, specific to the unit type.
// Valid values for unitType: Service, Socket, Target, Device, Mount, Automount, Snapshot, Timer, Swap, Path, Slice, Scope
// return "dbus.Error: Unknown interface" if the unitType is not the correct type of the unit
// GetServiceProperty returns property for given service name and property name.
func (c *Conn) GetServicePropertyContext(ctx context.Context, service string, propertyName string) (*Property, error) {
return c.getProperty(ctx, service, "org.freedesktop.systemd1.Service", propertyName)
}
// Deprecated: use GetUnitTypePropertiesContext instead.
func (c *Conn) GetUnitTypeProperties(unit string, unitType string) (map[string]interface{}, error) {
path := unitPath(unit)
return c.getProperties(path, "org.freedesktop.systemd1."+unitType)
return c.GetUnitTypePropertiesContext(context.Background(), unit, unitType)
}
// SetUnitProperties() may be used to modify certain unit properties at runtime.
// GetUnitTypePropertiesContext returns the extra properties for a unit, specific to the unit type.
// Valid values for unitType: Service, Socket, Target, Device, Mount, Automount, Snapshot, Timer, Swap, Path, Slice, Scope.
// Returns "dbus.Error: Unknown interface" error if the unitType is not the correct type of the unit.
func (c *Conn) GetUnitTypePropertiesContext(ctx context.Context, unit string, unitType string) (map[string]interface{}, error) {
path := unitPath(unit)
return c.getProperties(ctx, path, "org.freedesktop.systemd1."+unitType)
}
// Deprecated: use SetUnitPropertiesContext instead.
func (c *Conn) SetUnitProperties(name string, runtime bool, properties ...Property) error {
return c.SetUnitPropertiesContext(context.Background(), name, runtime, properties...)
}
// SetUnitPropertiesContext may be used to modify certain unit properties at runtime.
// Not all properties may be changed at runtime, but many resource management
// settings (primarily those in systemd.cgroup(5)) may. The changes are applied
// instantly, and stored on disk for future boots, unless runtime is true, in which
// case the settings only apply until the next reboot. name is the name of the unit
// to modify. properties are the settings to set, encoded as an array of property
// name and value pairs.
func (c *Conn) SetUnitProperties(name string, runtime bool, properties ...Property) error {
return c.sysobj.Call("org.freedesktop.systemd1.Manager.SetUnitProperties", 0, name, runtime, properties).Store()
func (c *Conn) SetUnitPropertiesContext(ctx context.Context, name string, runtime bool, properties ...Property) error {
return c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.SetUnitProperties", 0, name, runtime, properties).Store()
}
// Deprecated: use GetUnitTypePropertyContext instead.
func (c *Conn) GetUnitTypeProperty(unit string, unitType string, propertyName string) (*Property, error) {
return c.getProperty(unit, "org.freedesktop.systemd1."+unitType, propertyName)
return c.GetUnitTypePropertyContext(context.Background(), unit, unitType, propertyName)
}
// GetUnitTypePropertyContext takes a property name, a unit name, and a unit type,
// and returns a property value. For valid values of unitType, see GetUnitTypePropertiesContext.
func (c *Conn) GetUnitTypePropertyContext(ctx context.Context, unit string, unitType string, propertyName string) (*Property, error) {
return c.getProperty(ctx, unit, "org.freedesktop.systemd1."+unitType, propertyName)
}
type UnitStatus struct {
@ -294,36 +417,57 @@ func (c *Conn) listUnitsInternal(f storeFunc) ([]UnitStatus, error) {
return status, nil
}
// ListUnits returns an array with all currently loaded units. Note that
// Deprecated: use ListUnitsContext instead.
func (c *Conn) ListUnits() ([]UnitStatus, error) {
return c.ListUnitsContext(context.Background())
}
// ListUnitsContext returns an array with all currently loaded units. Note that
// units may be known by multiple names at the same time, and hence there might
// be more unit names loaded than actual units behind them.
// Also note that a unit is only loaded if it is active and/or enabled.
// Units that are both disabled and inactive will thus not be returned.
func (c *Conn) ListUnits() ([]UnitStatus, error) {
return c.listUnitsInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnits", 0).Store)
func (c *Conn) ListUnitsContext(ctx context.Context) ([]UnitStatus, error) {
return c.listUnitsInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnits", 0).Store)
}
// ListUnitsFiltered returns an array with units filtered by state.
// It takes a list of units' statuses to filter.
// Deprecated: use ListUnitsFilteredContext instead.
func (c *Conn) ListUnitsFiltered(states []string) ([]UnitStatus, error) {
return c.listUnitsInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitsFiltered", 0, states).Store)
return c.ListUnitsFilteredContext(context.Background(), states)
}
// ListUnitsByPatterns returns an array with units.
// ListUnitsFilteredContext returns an array with units filtered by state.
// It takes a list of units' statuses to filter.
func (c *Conn) ListUnitsFilteredContext(ctx context.Context, states []string) ([]UnitStatus, error) {
return c.listUnitsInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnitsFiltered", 0, states).Store)
}
// Deprecated: use ListUnitsByPatternsContext instead.
func (c *Conn) ListUnitsByPatterns(states []string, patterns []string) ([]UnitStatus, error) {
return c.ListUnitsByPatternsContext(context.Background(), states, patterns)
}
// ListUnitsByPatternsContext returns an array with units.
// It takes a list of units' statuses and names to filter.
// Note that units may be known by multiple names at the same time,
// and hence there might be more unit names loaded than actual units behind them.
func (c *Conn) ListUnitsByPatterns(states []string, patterns []string) ([]UnitStatus, error) {
return c.listUnitsInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitsByPatterns", 0, states, patterns).Store)
func (c *Conn) ListUnitsByPatternsContext(ctx context.Context, states []string, patterns []string) ([]UnitStatus, error) {
return c.listUnitsInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnitsByPatterns", 0, states, patterns).Store)
}
// ListUnitsByNames returns an array with units. It takes a list of units'
// names and returns an UnitStatus array. Comparing to ListUnitsByPatterns
// Deprecated: use ListUnitsByNamesContext instead.
func (c *Conn) ListUnitsByNames(units []string) ([]UnitStatus, error) {
return c.ListUnitsByNamesContext(context.Background(), units)
}
// ListUnitsByNamesContext returns an array with units. It takes a list of units'
// names and returns an UnitStatus array. Comparing to ListUnitsByPatternsContext
// method, this method returns statuses even for inactive or non-existing
// units. Input array should contain exact unit names, but not patterns.
// Note: Requires systemd v230 or higher
func (c *Conn) ListUnitsByNames(units []string) ([]UnitStatus, error) {
return c.listUnitsInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitsByNames", 0, units).Store)
//
// Requires systemd v230 or higher.
func (c *Conn) ListUnitsByNamesContext(ctx context.Context, units []string) ([]UnitStatus, error) {
return c.listUnitsInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnitsByNames", 0, units).Store)
}
type UnitFile struct {
@ -357,25 +501,43 @@ func (c *Conn) listUnitFilesInternal(f storeFunc) ([]UnitFile, error) {
return files, nil
}
// ListUnitFiles returns an array of all available units on disk.
// Deprecated: use ListUnitFilesContext instead.
func (c *Conn) ListUnitFiles() ([]UnitFile, error) {
return c.listUnitFilesInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitFiles", 0).Store)
return c.ListUnitFilesContext(context.Background())
}
// ListUnitFilesByPatterns returns an array of all available units on disk matched the patterns.
// ListUnitFiles returns an array of all available units on disk.
func (c *Conn) ListUnitFilesContext(ctx context.Context) ([]UnitFile, error) {
return c.listUnitFilesInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnitFiles", 0).Store)
}
// Deprecated: use ListUnitFilesByPatternsContext instead.
func (c *Conn) ListUnitFilesByPatterns(states []string, patterns []string) ([]UnitFile, error) {
return c.listUnitFilesInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitFilesByPatterns", 0, states, patterns).Store)
return c.ListUnitFilesByPatternsContext(context.Background(), states, patterns)
}
// ListUnitFilesByPatternsContext returns an array of all available units on disk matched the patterns.
func (c *Conn) ListUnitFilesByPatternsContext(ctx context.Context, states []string, patterns []string) ([]UnitFile, error) {
return c.listUnitFilesInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnitFilesByPatterns", 0, states, patterns).Store)
}
type LinkUnitFileChange EnableUnitFileChange
// LinkUnitFiles() links unit files (that are located outside of the
// Deprecated: use LinkUnitFilesContext instead.
func (c *Conn) LinkUnitFiles(files []string, runtime bool, force bool) ([]LinkUnitFileChange, error) {
return c.LinkUnitFilesContext(context.Background(), files, runtime, force)
}
// LinkUnitFilesContext links unit files (that are located outside of the
// usual unit search paths) into the unit search path.
//
// It takes a list of absolute paths to unit files to link and two
// booleans. The first boolean controls whether the unit shall be
// booleans.
//
// The first boolean controls whether the unit shall be
// enabled for runtime only (true, /run), or persistently (false,
// /etc).
//
// The second controls whether symlinks pointing to other units shall
// be replaced if necessary.
//
@ -383,9 +545,9 @@ type LinkUnitFileChange EnableUnitFileChange
// structures with three strings: the type of the change (one of symlink
// or unlink), the file name of the symlink and the destination of the
// symlink.
func (c *Conn) LinkUnitFiles(files []string, runtime bool, force bool) ([]LinkUnitFileChange, error) {
func (c *Conn) LinkUnitFilesContext(ctx context.Context, files []string, runtime bool, force bool) ([]LinkUnitFileChange, error) {
result := make([][]interface{}, 0)
err := c.sysobj.Call("org.freedesktop.systemd1.Manager.LinkUnitFiles", 0, files, runtime, force).Store(&result)
err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.LinkUnitFiles", 0, files, runtime, force).Store(&result)
if err != nil {
return nil, err
}
@ -409,8 +571,13 @@ func (c *Conn) LinkUnitFiles(files []string, runtime bool, force bool) ([]LinkUn
return changes, nil
}
// EnableUnitFiles() may be used to enable one or more units in the system (by
// creating symlinks to them in /etc or /run).
// Deprecated: use EnableUnitFilesContext instead.
func (c *Conn) EnableUnitFiles(files []string, runtime bool, force bool) (bool, []EnableUnitFileChange, error) {
return c.EnableUnitFilesContext(context.Background(), files, runtime, force)
}
// EnableUnitFilesContext may be used to enable one or more units in the system
// (by creating symlinks to them in /etc or /run).
//
// It takes a list of unit files to enable (either just file names or full
// absolute paths if the unit files are residing outside the usual unit
@ -425,11 +592,11 @@ func (c *Conn) LinkUnitFiles(files []string, runtime bool, force bool) ([]LinkUn
// structures with three strings: the type of the change (one of symlink
// or unlink), the file name of the symlink and the destination of the
// symlink.
func (c *Conn) EnableUnitFiles(files []string, runtime bool, force bool) (bool, []EnableUnitFileChange, error) {
func (c *Conn) EnableUnitFilesContext(ctx context.Context, files []string, runtime bool, force bool) (bool, []EnableUnitFileChange, error) {
var carries_install_info bool
result := make([][]interface{}, 0)
err := c.sysobj.Call("org.freedesktop.systemd1.Manager.EnableUnitFiles", 0, files, runtime, force).Store(&carries_install_info, &result)
err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.EnableUnitFiles", 0, files, runtime, force).Store(&carries_install_info, &result)
if err != nil {
return false, nil, err
}
@ -459,8 +626,13 @@ type EnableUnitFileChange struct {
Destination string // Destination of the symlink
}
// DisableUnitFiles() may be used to disable one or more units in the system (by
// removing symlinks to them from /etc or /run).
// Deprecated: use DisableUnitFilesContext instead.
func (c *Conn) DisableUnitFiles(files []string, runtime bool) ([]DisableUnitFileChange, error) {
return c.DisableUnitFilesContext(context.Background(), files, runtime)
}
// DisableUnitFilesContext may be used to disable one or more units in the
// system (by removing symlinks to them from /etc or /run).
//
// It takes a list of unit files to disable (either just file names or full
// absolute paths if the unit files are residing outside the usual unit
@ -471,9 +643,9 @@ type EnableUnitFileChange struct {
// consists of structures with three strings: the type of the change (one of
// symlink or unlink), the file name of the symlink and the destination of the
// symlink.
func (c *Conn) DisableUnitFiles(files []string, runtime bool) ([]DisableUnitFileChange, error) {
func (c *Conn) DisableUnitFilesContext(ctx context.Context, files []string, runtime bool) ([]DisableUnitFileChange, error) {
result := make([][]interface{}, 0)
err := c.sysobj.Call("org.freedesktop.systemd1.Manager.DisableUnitFiles", 0, files, runtime).Store(&result)
err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.DisableUnitFiles", 0, files, runtime).Store(&result)
if err != nil {
return nil, err
}
@ -503,18 +675,23 @@ type DisableUnitFileChange struct {
Destination string // Destination of the symlink
}
// MaskUnitFiles masks one or more units in the system
//
// It takes three arguments:
// * list of units to mask (either just file names or full
// absolute paths if the unit files are residing outside
// the usual unit search paths)
// * runtime to specify whether the unit was enabled for runtime
// only (true, /run/systemd/..), or persistently (false, /etc/systemd/..)
// * force flag
// Deprecated: use MaskUnitFilesContext instead.
func (c *Conn) MaskUnitFiles(files []string, runtime bool, force bool) ([]MaskUnitFileChange, error) {
return c.MaskUnitFilesContext(context.Background(), files, runtime, force)
}
// MaskUnitFilesContext masks one or more units in the system.
//
// The files argument contains a list of units to mask (either just file names
// or full absolute paths if the unit files are residing outside the usual unit
// search paths).
//
// The runtime argument is used to specify whether the unit was enabled for
// runtime only (true, /run/systemd/..), or persistently (false,
// /etc/systemd/..).
func (c *Conn) MaskUnitFilesContext(ctx context.Context, files []string, runtime bool, force bool) ([]MaskUnitFileChange, error) {
result := make([][]interface{}, 0)
err := c.sysobj.Call("org.freedesktop.systemd1.Manager.MaskUnitFiles", 0, files, runtime, force).Store(&result)
err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.MaskUnitFiles", 0, files, runtime, force).Store(&result)
if err != nil {
return nil, err
}
@ -544,17 +721,21 @@ type MaskUnitFileChange struct {
Destination string // Destination of the symlink
}
// UnmaskUnitFiles unmasks one or more units in the system
//
// It takes two arguments:
// * list of unit files to mask (either just file names or full
// absolute paths if the unit files are residing outside
// the usual unit search paths)
// * runtime to specify whether the unit was enabled for runtime
// only (true, /run/systemd/..), or persistently (false, /etc/systemd/..)
// Deprecated: use UnmaskUnitFilesContext instead.
func (c *Conn) UnmaskUnitFiles(files []string, runtime bool) ([]UnmaskUnitFileChange, error) {
return c.UnmaskUnitFilesContext(context.Background(), files, runtime)
}
// UnmaskUnitFilesContext unmasks one or more units in the system.
//
// It takes the list of unit files to mask (either just file names or full
// absolute paths if the unit files are residing outside the usual unit search
// paths), and a boolean runtime flag to specify whether the unit was enabled
// for runtime only (true, /run/systemd/..), or persistently (false,
// /etc/systemd/..).
func (c *Conn) UnmaskUnitFilesContext(ctx context.Context, files []string, runtime bool) ([]UnmaskUnitFileChange, error) {
result := make([][]interface{}, 0)
err := c.sysobj.Call("org.freedesktop.systemd1.Manager.UnmaskUnitFiles", 0, files, runtime).Store(&result)
err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.UnmaskUnitFiles", 0, files, runtime).Store(&result)
if err != nil {
return nil, err
}
@ -584,17 +765,66 @@ type UnmaskUnitFileChange struct {
Destination string // Destination of the symlink
}
// Reload instructs systemd to scan for and reload unit files. This is
// equivalent to a 'systemctl daemon-reload'.
// Deprecated: use ReloadContext instead.
func (c *Conn) Reload() error {
return c.sysobj.Call("org.freedesktop.systemd1.Manager.Reload", 0).Store()
return c.ReloadContext(context.Background())
}
// ReloadContext instructs systemd to scan for and reload unit files. This is
// an equivalent to systemctl daemon-reload.
func (c *Conn) ReloadContext(ctx context.Context) error {
return c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.Reload", 0).Store()
}
func unitPath(name string) dbus.ObjectPath {
return dbus.ObjectPath("/org/freedesktop/systemd1/unit/" + PathBusEscape(name))
}
// unitName returns the unescaped base element of the supplied escaped path
// unitName returns the unescaped base element of the supplied escaped path.
func unitName(dpath dbus.ObjectPath) string {
return pathBusUnescape(path.Base(string(dpath)))
}
// JobStatus holds a currently queued job definition.
type JobStatus struct {
Id uint32 // The numeric job id
Unit string // The primary unit name for this job
JobType string // The job type as string
Status string // The job state as string
JobPath dbus.ObjectPath // The job object path
UnitPath dbus.ObjectPath // The unit object path
}
// Deprecated: use ListJobsContext instead.
func (c *Conn) ListJobs() ([]JobStatus, error) {
return c.ListJobsContext(context.Background())
}
// ListJobsContext returns an array with all currently queued jobs.
func (c *Conn) ListJobsContext(ctx context.Context) ([]JobStatus, error) {
return c.listJobsInternal(ctx)
}
func (c *Conn) listJobsInternal(ctx context.Context) ([]JobStatus, error) {
result := make([][]interface{}, 0)
if err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListJobs", 0).Store(&result); err != nil {
return nil, err
}
resultInterface := make([]interface{}, len(result))
for i := range result {
resultInterface[i] = result[i]
}
status := make([]JobStatus, len(result))
statusInterface := make([]interface{}, len(status))
for i := range status {
statusInterface[i] = &status[i]
}
if err := dbus.Store(resultInterface, statusInterface...); err != nil {
return nil, err
}
return status, nil
}

View File

@ -0,0 +1,17 @@
ISC License
Copyright (c) 2013-2017 The btcsuite developers
Copyright (c) 2015-2020 The Decred developers
Copyright (c) 2017 The Lightning Network Developers
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

View File

@ -0,0 +1,72 @@
secp256k1
=========
[![Build Status](https://github.com/decred/dcrd/workflows/Build%20and%20Test/badge.svg)](https://github.com/decred/dcrd/actions)
[![ISC License](https://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
[![Doc](https://img.shields.io/badge/doc-reference-blue.svg)](https://pkg.go.dev/github.com/decred/dcrd/dcrec/secp256k1/v4)
Package secp256k1 implements optimized secp256k1 elliptic curve operations.
This package provides an optimized pure Go implementation of elliptic curve
cryptography operations over the secp256k1 curve as well as data structures and
functions for working with public and private secp256k1 keys. See
https://www.secg.org/sec2-v2.pdf for details on the standard.
In addition, sub packages are provided to produce, verify, parse, and serialize
ECDSA signatures and EC-Schnorr-DCRv0 (a custom Schnorr-based signature scheme
specific to Decred) signatures. See the README.md files in the relevant sub
packages for more details about those aspects.
An overview of the features provided by this package are as follows:
- Private key generation, serialization, and parsing
- Public key generation, serialization and parsing per ANSI X9.62-1998
- Parses uncompressed, compressed, and hybrid public keys
- Serializes uncompressed and compressed public keys
- Specialized types for performing optimized and constant time field operations
- `FieldVal` type for working modulo the secp256k1 field prime
- `ModNScalar` type for working modulo the secp256k1 group order
- Elliptic curve operations in Jacobian projective coordinates
- Point addition
- Point doubling
- Scalar multiplication with an arbitrary point
- Scalar multiplication with the base point (group generator)
- Point decompression from a given x coordinate
- Nonce generation via RFC6979 with support for extra data and version
information that can be used to prevent nonce reuse between signing algorithms
It also provides an implementation of the Go standard library `crypto/elliptic`
`Curve` interface via the `S256` function so that it may be used with other
packages in the standard library such as `crypto/tls`, `crypto/x509`, and
`crypto/ecdsa`. However, in the case of ECDSA, it is highly recommended to use
the `ecdsa` sub package of this package instead since it is optimized
specifically for secp256k1 and is significantly faster as a result.
Although this package was primarily written for dcrd, it has intentionally been
designed so it can be used as a standalone package for any projects needing to
use optimized secp256k1 elliptic curve cryptography.
Finally, a comprehensive suite of tests is provided to provide a high level of
quality assurance.
## secp256k1 use in Decred
At the time of this writing, the primary public key cryptography in widespread
use on the Decred network used to secure coins is based on elliptic curves
defined by the secp256k1 domain parameters.
## Installation and Updating
This package is part of the `github.com/decred/dcrd/dcrec/secp256k1/v4` module.
Use the standard go tooling for working with modules to incorporate it.
## Examples
* [Encryption](https://pkg.go.dev/github.com/decred/dcrd/dcrec/secp256k1/v4#example-package-EncryptDecryptMessage)
Demonstrates encrypting and decrypting a message using a shared key derived
through ECDHE.
## License
Package secp256k1 is licensed under the [copyfree](http://copyfree.org) ISC
License.

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,943 @@
// Copyright (c) 2015-2021 The Decred developers
// Copyright 2013-2014 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package secp256k1
import (
"encoding/hex"
"math/big"
)
// References:
// [SECG]: Recommended Elliptic Curve Domain Parameters
// https://www.secg.org/sec2-v2.pdf
//
// [GECC]: Guide to Elliptic Curve Cryptography (Hankerson, Menezes, Vanstone)
//
// [BRID]: On Binary Representations of Integers with Digits -1, 0, 1
// (Prodinger, Helmut)
// All group operations are performed using Jacobian coordinates. For a given
// (x, y) position on the curve, the Jacobian coordinates are (x1, y1, z1)
// where x = x1/z1^2 and y = y1/z1^3.
// hexToFieldVal converts the passed hex string into a FieldVal and will panic
// if there is an error. This is only provided for the hard-coded constants so
// errors in the source code can be detected. It will only (and must only) be
// called with hard-coded values.
func hexToFieldVal(s string) *FieldVal {
b, err := hex.DecodeString(s)
if err != nil {
panic("invalid hex in source file: " + s)
}
var f FieldVal
if overflow := f.SetByteSlice(b); overflow {
panic("hex in source file overflows mod P: " + s)
}
return &f
}
var (
// Next 6 constants are from Hal Finney's bitcointalk.org post:
// https://bitcointalk.org/index.php?topic=3238.msg45565#msg45565
// May he rest in peace.
//
// They have also been independently derived from the code in the
// EndomorphismVectors function in genstatics.go.
endomorphismLambda = fromHex("5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72")
endomorphismBeta = hexToFieldVal("7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee")
endomorphismA1 = fromHex("3086d221a7d46bcde86c90e49284eb15")
endomorphismB1 = fromHex("-e4437ed6010e88286f547fa90abfe4c3")
endomorphismA2 = fromHex("114ca50f7a8e2f3f657c1108d9d44cfd8")
endomorphismB2 = fromHex("3086d221a7d46bcde86c90e49284eb15")
// Alternatively, the following parameters are valid as well, however, they
// seem to be about 8% slower in practice.
//
// endomorphismLambda = fromHex("AC9C52B33FA3CF1F5AD9E3FD77ED9BA4A880B9FC8EC739C2E0CFC810B51283CE")
// endomorphismBeta = hexToFieldVal("851695D49A83F8EF919BB86153CBCB16630FB68AED0A766A3EC693D68E6AFA40")
// endomorphismA1 = fromHex("E4437ED6010E88286F547FA90ABFE4C3")
// endomorphismB1 = fromHex("-3086D221A7D46BCDE86C90E49284EB15")
// endomorphismA2 = fromHex("3086D221A7D46BCDE86C90E49284EB15")
// endomorphismB2 = fromHex("114CA50F7A8E2F3F657C1108D9D44CFD8")
)
// JacobianPoint is an element of the group formed by the secp256k1 curve in
// Jacobian projective coordinates and thus represents a point on the curve.
type JacobianPoint struct {
// The X coordinate in Jacobian projective coordinates. The affine point is
// X/z^2.
X FieldVal
// The Y coordinate in Jacobian projective coordinates. The affine point is
// Y/z^3.
Y FieldVal
// The Z coordinate in Jacobian projective coordinates.
Z FieldVal
}
// MakeJacobianPoint returns a Jacobian point with the provided X, Y, and Z
// coordinates.
func MakeJacobianPoint(x, y, z *FieldVal) JacobianPoint {
var p JacobianPoint
p.X.Set(x)
p.Y.Set(y)
p.Z.Set(z)
return p
}
// Set sets the Jacobian point to the provided point.
func (p *JacobianPoint) Set(other *JacobianPoint) {
p.X.Set(&other.X)
p.Y.Set(&other.Y)
p.Z.Set(&other.Z)
}
// ToAffine reduces the Z value of the existing point to 1 effectively
// making it an affine coordinate in constant time. The point will be
// normalized.
func (p *JacobianPoint) ToAffine() {
// Inversions are expensive and both point addition and point doubling
// are faster when working with points that have a z value of one. So,
// if the point needs to be converted to affine, go ahead and normalize
// the point itself at the same time as the calculation is the same.
var zInv, tempZ FieldVal
zInv.Set(&p.Z).Inverse() // zInv = Z^-1
tempZ.SquareVal(&zInv) // tempZ = Z^-2
p.X.Mul(&tempZ) // X = X/Z^2 (mag: 1)
p.Y.Mul(tempZ.Mul(&zInv)) // Y = Y/Z^3 (mag: 1)
p.Z.SetInt(1) // Z = 1 (mag: 1)
// Normalize the x and y values.
p.X.Normalize()
p.Y.Normalize()
}
// addZ1AndZ2EqualsOne adds two Jacobian points that are already known to have
// z values of 1 and stores the result in the provided result param. That is to
// say result = p1 + p2. It performs faster addition than the generic add
// routine since less arithmetic is needed due to the ability to avoid the z
// value multiplications.
//
// NOTE: The points must be normalized for this function to return the correct
// result. The resulting point will be normalized.
func addZ1AndZ2EqualsOne(p1, p2, result *JacobianPoint) {
// To compute the point addition efficiently, this implementation splits
// the equation into intermediate elements which are used to minimize
// the number of field multiplications using the method shown at:
// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-mmadd-2007-bl
//
// In particular it performs the calculations using the following:
// H = X2-X1, HH = H^2, I = 4*HH, J = H*I, r = 2*(Y2-Y1), V = X1*I
// X3 = r^2-J-2*V, Y3 = r*(V-X3)-2*Y1*J, Z3 = 2*H
//
// This results in a cost of 4 field multiplications, 2 field squarings,
// 6 field additions, and 5 integer multiplications.
x1, y1 := &p1.X, &p1.Y
x2, y2 := &p2.X, &p2.Y
x3, y3, z3 := &result.X, &result.Y, &result.Z
// When the x coordinates are the same for two points on the curve, the
// y coordinates either must be the same, in which case it is point
// doubling, or they are opposite and the result is the point at
// infinity per the group law for elliptic curve cryptography.
if x1.Equals(x2) {
if y1.Equals(y2) {
// Since x1 == x2 and y1 == y2, point doubling must be
// done, otherwise the addition would end up dividing
// by zero.
DoubleNonConst(p1, result)
return
}
// Since x1 == x2 and y1 == -y2, the sum is the point at
// infinity per the group law.
x3.SetInt(0)
y3.SetInt(0)
z3.SetInt(0)
return
}
// Calculate X3, Y3, and Z3 according to the intermediate elements
// breakdown above.
var h, i, j, r, v FieldVal
var negJ, neg2V, negX3 FieldVal
h.Set(x1).Negate(1).Add(x2) // H = X2-X1 (mag: 3)
i.SquareVal(&h).MulInt(4) // I = 4*H^2 (mag: 4)
j.Mul2(&h, &i) // J = H*I (mag: 1)
r.Set(y1).Negate(1).Add(y2).MulInt(2) // r = 2*(Y2-Y1) (mag: 6)
v.Mul2(x1, &i) // V = X1*I (mag: 1)
negJ.Set(&j).Negate(1) // negJ = -J (mag: 2)
neg2V.Set(&v).MulInt(2).Negate(2) // neg2V = -(2*V) (mag: 3)
x3.Set(&r).Square().Add(&negJ).Add(&neg2V) // X3 = r^2-J-2*V (mag: 6)
negX3.Set(x3).Negate(6) // negX3 = -X3 (mag: 7)
j.Mul(y1).MulInt(2).Negate(2) // J = -(2*Y1*J) (mag: 3)
y3.Set(&v).Add(&negX3).Mul(&r).Add(&j) // Y3 = r*(V-X3)-2*Y1*J (mag: 4)
z3.Set(&h).MulInt(2) // Z3 = 2*H (mag: 6)
// Normalize the resulting field values to a magnitude of 1 as needed.
x3.Normalize()
y3.Normalize()
z3.Normalize()
}
// addZ1EqualsZ2 adds two Jacobian points that are already known to have the
// same z value and stores the result in the provided result param. That is to
// say result = p1 + p2. It performs faster addition than the generic add
// routine since less arithmetic is needed due to the known equivalence.
//
// NOTE: The points must be normalized for this function to return the correct
// result. The resulting point will be normalized.
func addZ1EqualsZ2(p1, p2, result *JacobianPoint) {
// To compute the point addition efficiently, this implementation splits
// the equation into intermediate elements which are used to minimize
// the number of field multiplications using a slightly modified version
// of the method shown at:
// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-mmadd-2007-bl
//
// In particular it performs the calculations using the following:
// A = X2-X1, B = A^2, C=Y2-Y1, D = C^2, E = X1*B, F = X2*B
// X3 = D-E-F, Y3 = C*(E-X3)-Y1*(F-E), Z3 = Z1*A
//
// This results in a cost of 5 field multiplications, 2 field squarings,
// 9 field additions, and 0 integer multiplications.
x1, y1, z1 := &p1.X, &p1.Y, &p1.Z
x2, y2 := &p2.X, &p2.Y
x3, y3, z3 := &result.X, &result.Y, &result.Z
// When the x coordinates are the same for two points on the curve, the
// y coordinates either must be the same, in which case it is point
// doubling, or they are opposite and the result is the point at
// infinity per the group law for elliptic curve cryptography.
if x1.Equals(x2) {
if y1.Equals(y2) {
// Since x1 == x2 and y1 == y2, point doubling must be
// done, otherwise the addition would end up dividing
// by zero.
DoubleNonConst(p1, result)
return
}
// Since x1 == x2 and y1 == -y2, the sum is the point at
// infinity per the group law.
x3.SetInt(0)
y3.SetInt(0)
z3.SetInt(0)
return
}
// Calculate X3, Y3, and Z3 according to the intermediate elements
// breakdown above.
var a, b, c, d, e, f FieldVal
var negX1, negY1, negE, negX3 FieldVal
negX1.Set(x1).Negate(1) // negX1 = -X1 (mag: 2)
negY1.Set(y1).Negate(1) // negY1 = -Y1 (mag: 2)
a.Set(&negX1).Add(x2) // A = X2-X1 (mag: 3)
b.SquareVal(&a) // B = A^2 (mag: 1)
c.Set(&negY1).Add(y2) // C = Y2-Y1 (mag: 3)
d.SquareVal(&c) // D = C^2 (mag: 1)
e.Mul2(x1, &b) // E = X1*B (mag: 1)
negE.Set(&e).Negate(1) // negE = -E (mag: 2)
f.Mul2(x2, &b) // F = X2*B (mag: 1)
x3.Add2(&e, &f).Negate(3).Add(&d) // X3 = D-E-F (mag: 5)
negX3.Set(x3).Negate(5).Normalize() // negX3 = -X3 (mag: 1)
y3.Set(y1).Mul(f.Add(&negE)).Negate(3) // Y3 = -(Y1*(F-E)) (mag: 4)
y3.Add(e.Add(&negX3).Mul(&c)) // Y3 = C*(E-X3)+Y3 (mag: 5)
z3.Mul2(z1, &a) // Z3 = Z1*A (mag: 1)
// Normalize the resulting field values to a magnitude of 1 as needed.
x3.Normalize()
y3.Normalize()
z3.Normalize()
}
// addZ2EqualsOne adds two Jacobian points when the second point is already
// known to have a z value of 1 (and the z value for the first point is not 1)
// and stores the result in the provided result param. That is to say result =
// p1 + p2. It performs faster addition than the generic add routine since
// less arithmetic is needed due to the ability to avoid multiplications by the
// second point's z value.
//
// NOTE: The points must be normalized for this function to return the correct
// result. The resulting point will be normalized.
func addZ2EqualsOne(p1, p2, result *JacobianPoint) {
// To compute the point addition efficiently, this implementation splits
// the equation into intermediate elements which are used to minimize
// the number of field multiplications using the method shown at:
// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl
//
// In particular it performs the calculations using the following:
// Z1Z1 = Z1^2, U2 = X2*Z1Z1, S2 = Y2*Z1*Z1Z1, H = U2-X1, HH = H^2,
// I = 4*HH, J = H*I, r = 2*(S2-Y1), V = X1*I
// X3 = r^2-J-2*V, Y3 = r*(V-X3)-2*Y1*J, Z3 = (Z1+H)^2-Z1Z1-HH
//
// This results in a cost of 7 field multiplications, 4 field squarings,
// 9 field additions, and 4 integer multiplications.
x1, y1, z1 := &p1.X, &p1.Y, &p1.Z
x2, y2 := &p2.X, &p2.Y
x3, y3, z3 := &result.X, &result.Y, &result.Z
// When the x coordinates are the same for two points on the curve, the
// y coordinates either must be the same, in which case it is point
// doubling, or they are opposite and the result is the point at
// infinity per the group law for elliptic curve cryptography. Since
// any number of Jacobian coordinates can represent the same affine
// point, the x and y values need to be converted to like terms. Due to
// the assumption made for this function that the second point has a z
// value of 1 (z2=1), the first point is already "converted".
var z1z1, u2, s2 FieldVal
z1z1.SquareVal(z1) // Z1Z1 = Z1^2 (mag: 1)
u2.Set(x2).Mul(&z1z1).Normalize() // U2 = X2*Z1Z1 (mag: 1)
s2.Set(y2).Mul(&z1z1).Mul(z1).Normalize() // S2 = Y2*Z1*Z1Z1 (mag: 1)
if x1.Equals(&u2) {
if y1.Equals(&s2) {
// Since x1 == x2 and y1 == y2, point doubling must be
// done, otherwise the addition would end up dividing
// by zero.
DoubleNonConst(p1, result)
return
}
// Since x1 == x2 and y1 == -y2, the sum is the point at
// infinity per the group law.
x3.SetInt(0)
y3.SetInt(0)
z3.SetInt(0)
return
}
// Calculate X3, Y3, and Z3 according to the intermediate elements
// breakdown above.
var h, hh, i, j, r, rr, v FieldVal
var negX1, negY1, negX3 FieldVal
negX1.Set(x1).Negate(1) // negX1 = -X1 (mag: 2)
h.Add2(&u2, &negX1) // H = U2-X1 (mag: 3)
hh.SquareVal(&h) // HH = H^2 (mag: 1)
i.Set(&hh).MulInt(4) // I = 4 * HH (mag: 4)
j.Mul2(&h, &i) // J = H*I (mag: 1)
negY1.Set(y1).Negate(1) // negY1 = -Y1 (mag: 2)
r.Set(&s2).Add(&negY1).MulInt(2) // r = 2*(S2-Y1) (mag: 6)
rr.SquareVal(&r) // rr = r^2 (mag: 1)
v.Mul2(x1, &i) // V = X1*I (mag: 1)
x3.Set(&v).MulInt(2).Add(&j).Negate(3) // X3 = -(J+2*V) (mag: 4)
x3.Add(&rr) // X3 = r^2+X3 (mag: 5)
negX3.Set(x3).Negate(5) // negX3 = -X3 (mag: 6)
y3.Set(y1).Mul(&j).MulInt(2).Negate(2) // Y3 = -(2*Y1*J) (mag: 3)
y3.Add(v.Add(&negX3).Mul(&r)) // Y3 = r*(V-X3)+Y3 (mag: 4)
z3.Add2(z1, &h).Square() // Z3 = (Z1+H)^2 (mag: 1)
z3.Add(z1z1.Add(&hh).Negate(2)) // Z3 = Z3-(Z1Z1+HH) (mag: 4)
// Normalize the resulting field values to a magnitude of 1 as needed.
x3.Normalize()
y3.Normalize()
z3.Normalize()
}
// addGeneric adds two Jacobian points without any assumptions about the z
// values of the two points and stores the result in the provided result param.
// That is to say result = p1 + p2. It is the slowest of the add routines due
// to requiring the most arithmetic.
//
// NOTE: The points must be normalized for this function to return the correct
// result. The resulting point will be normalized.
func addGeneric(p1, p2, result *JacobianPoint) {
// To compute the point addition efficiently, this implementation splits
// the equation into intermediate elements which are used to minimize
// the number of field multiplications using the method shown at:
// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl
//
// In particular it performs the calculations using the following:
// Z1Z1 = Z1^2, Z2Z2 = Z2^2, U1 = X1*Z2Z2, U2 = X2*Z1Z1, S1 = Y1*Z2*Z2Z2
// S2 = Y2*Z1*Z1Z1, H = U2-U1, I = (2*H)^2, J = H*I, r = 2*(S2-S1)
// V = U1*I
// X3 = r^2-J-2*V, Y3 = r*(V-X3)-2*S1*J, Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2)*H
//
// This results in a cost of 11 field multiplications, 5 field squarings,
// 9 field additions, and 4 integer multiplications.
x1, y1, z1 := &p1.X, &p1.Y, &p1.Z
x2, y2, z2 := &p2.X, &p2.Y, &p2.Z
x3, y3, z3 := &result.X, &result.Y, &result.Z
// When the x coordinates are the same for two points on the curve, the
// y coordinates either must be the same, in which case it is point
// doubling, or they are opposite and the result is the point at
// infinity. Since any number of Jacobian coordinates can represent the
// same affine point, the x and y values need to be converted to like
// terms.
var z1z1, z2z2, u1, u2, s1, s2 FieldVal
z1z1.SquareVal(z1) // Z1Z1 = Z1^2 (mag: 1)
z2z2.SquareVal(z2) // Z2Z2 = Z2^2 (mag: 1)
u1.Set(x1).Mul(&z2z2).Normalize() // U1 = X1*Z2Z2 (mag: 1)
u2.Set(x2).Mul(&z1z1).Normalize() // U2 = X2*Z1Z1 (mag: 1)
s1.Set(y1).Mul(&z2z2).Mul(z2).Normalize() // S1 = Y1*Z2*Z2Z2 (mag: 1)
s2.Set(y2).Mul(&z1z1).Mul(z1).Normalize() // S2 = Y2*Z1*Z1Z1 (mag: 1)
if u1.Equals(&u2) {
if s1.Equals(&s2) {
// Since x1 == x2 and y1 == y2, point doubling must be
// done, otherwise the addition would end up dividing
// by zero.
DoubleNonConst(p1, result)
return
}
// Since x1 == x2 and y1 == -y2, the sum is the point at
// infinity per the group law.
x3.SetInt(0)
y3.SetInt(0)
z3.SetInt(0)
return
}
// Calculate X3, Y3, and Z3 according to the intermediate elements
// breakdown above.
var h, i, j, r, rr, v FieldVal
var negU1, negS1, negX3 FieldVal
negU1.Set(&u1).Negate(1) // negU1 = -U1 (mag: 2)
h.Add2(&u2, &negU1) // H = U2-U1 (mag: 3)
i.Set(&h).MulInt(2).Square() // I = (2*H)^2 (mag: 2)
j.Mul2(&h, &i) // J = H*I (mag: 1)
negS1.Set(&s1).Negate(1) // negS1 = -S1 (mag: 2)
r.Set(&s2).Add(&negS1).MulInt(2) // r = 2*(S2-S1) (mag: 6)
rr.SquareVal(&r) // rr = r^2 (mag: 1)
v.Mul2(&u1, &i) // V = U1*I (mag: 1)
x3.Set(&v).MulInt(2).Add(&j).Negate(3) // X3 = -(J+2*V) (mag: 4)
x3.Add(&rr) // X3 = r^2+X3 (mag: 5)
negX3.Set(x3).Negate(5) // negX3 = -X3 (mag: 6)
y3.Mul2(&s1, &j).MulInt(2).Negate(2) // Y3 = -(2*S1*J) (mag: 3)
y3.Add(v.Add(&negX3).Mul(&r)) // Y3 = r*(V-X3)+Y3 (mag: 4)
z3.Add2(z1, z2).Square() // Z3 = (Z1+Z2)^2 (mag: 1)
z3.Add(z1z1.Add(&z2z2).Negate(2)) // Z3 = Z3-(Z1Z1+Z2Z2) (mag: 4)
z3.Mul(&h) // Z3 = Z3*H (mag: 1)
// Normalize the resulting field values to a magnitude of 1 as needed.
x3.Normalize()
y3.Normalize()
z3.Normalize()
}
// AddNonConst adds the passed Jacobian points together and stores the result in
// the provided result param in *non-constant* time.
//
// NOTE: The points must be normalized for this function to return the correct
// result. The resulting point will be normalized.
func AddNonConst(p1, p2, result *JacobianPoint) {
// A point at infinity is the identity according to the group law for
// elliptic curve cryptography. Thus, ∞ + P = P and P + ∞ = P.
if (p1.X.IsZero() && p1.Y.IsZero()) || p1.Z.IsZero() {
result.Set(p2)
return
}
if (p2.X.IsZero() && p2.Y.IsZero()) || p2.Z.IsZero() {
result.Set(p1)
return
}
// Faster point addition can be achieved when certain assumptions are
// met. For example, when both points have the same z value, arithmetic
// on the z values can be avoided. This section thus checks for these
// conditions and calls an appropriate add function which is accelerated
// by using those assumptions.
isZ1One := p1.Z.IsOne()
isZ2One := p2.Z.IsOne()
switch {
case isZ1One && isZ2One:
addZ1AndZ2EqualsOne(p1, p2, result)
return
case p1.Z.Equals(&p2.Z):
addZ1EqualsZ2(p1, p2, result)
return
case isZ2One:
addZ2EqualsOne(p1, p2, result)
return
}
// None of the above assumptions are true, so fall back to generic
// point addition.
addGeneric(p1, p2, result)
}
// doubleZ1EqualsOne performs point doubling on the passed Jacobian point when
// the point is already known to have a z value of 1 and stores the result in
// the provided result param. That is to say result = 2*p. It performs faster
// point doubling than the generic routine since less arithmetic is needed due
// to the ability to avoid multiplication by the z value.
//
// NOTE: The resulting point will be normalized.
func doubleZ1EqualsOne(p, result *JacobianPoint) {
// This function uses the assumptions that z1 is 1, thus the point
// doubling formulas reduce to:
//
// X3 = (3*X1^2)^2 - 8*X1*Y1^2
// Y3 = (3*X1^2)*(4*X1*Y1^2 - X3) - 8*Y1^4
// Z3 = 2*Y1
//
// To compute the above efficiently, this implementation splits the
// equation into intermediate elements which are used to minimize the
// number of field multiplications in favor of field squarings which
// are roughly 35% faster than field multiplications with the current
// implementation at the time this was written.
//
// This uses a slightly modified version of the method shown at:
// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl
//
// In particular it performs the calculations using the following:
// A = X1^2, B = Y1^2, C = B^2, D = 2*((X1+B)^2-A-C)
// E = 3*A, F = E^2, X3 = F-2*D, Y3 = E*(D-X3)-8*C
// Z3 = 2*Y1
//
// This results in a cost of 1 field multiplication, 5 field squarings,
// 6 field additions, and 5 integer multiplications.
x1, y1 := &p.X, &p.Y
x3, y3, z3 := &result.X, &result.Y, &result.Z
var a, b, c, d, e, f FieldVal
z3.Set(y1).MulInt(2) // Z3 = 2*Y1 (mag: 2)
a.SquareVal(x1) // A = X1^2 (mag: 1)
b.SquareVal(y1) // B = Y1^2 (mag: 1)
c.SquareVal(&b) // C = B^2 (mag: 1)
b.Add(x1).Square() // B = (X1+B)^2 (mag: 1)
d.Set(&a).Add(&c).Negate(2) // D = -(A+C) (mag: 3)
d.Add(&b).MulInt(2) // D = 2*(B+D)(mag: 8)
e.Set(&a).MulInt(3) // E = 3*A (mag: 3)
f.SquareVal(&e) // F = E^2 (mag: 1)
x3.Set(&d).MulInt(2).Negate(16) // X3 = -(2*D) (mag: 17)
x3.Add(&f) // X3 = F+X3 (mag: 18)
f.Set(x3).Negate(18).Add(&d).Normalize() // F = D-X3 (mag: 1)
y3.Set(&c).MulInt(8).Negate(8) // Y3 = -(8*C) (mag: 9)
y3.Add(f.Mul(&e)) // Y3 = E*F+Y3 (mag: 10)
// Normalize the field values back to a magnitude of 1.
x3.Normalize()
y3.Normalize()
z3.Normalize()
}
// doubleGeneric performs point doubling on the passed Jacobian point without
// any assumptions about the z value and stores the result in the provided
// result param. That is to say result = 2*p. It is the slowest of the point
// doubling routines due to requiring the most arithmetic.
//
// NOTE: The resulting point will be normalized.
func doubleGeneric(p, result *JacobianPoint) {
// Point doubling formula for Jacobian coordinates for the secp256k1
// curve:
//
// X3 = (3*X1^2)^2 - 8*X1*Y1^2
// Y3 = (3*X1^2)*(4*X1*Y1^2 - X3) - 8*Y1^4
// Z3 = 2*Y1*Z1
//
// To compute the above efficiently, this implementation splits the
// equation into intermediate elements which are used to minimize the
// number of field multiplications in favor of field squarings which
// are roughly 35% faster than field multiplications with the current
// implementation at the time this was written.
//
// This uses a slightly modified version of the method shown at:
// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l
//
// In particular it performs the calculations using the following:
// A = X1^2, B = Y1^2, C = B^2, D = 2*((X1+B)^2-A-C)
// E = 3*A, F = E^2, X3 = F-2*D, Y3 = E*(D-X3)-8*C
// Z3 = 2*Y1*Z1
//
// This results in a cost of 1 field multiplication, 5 field squarings,
// 6 field additions, and 5 integer multiplications.
x1, y1, z1 := &p.X, &p.Y, &p.Z
x3, y3, z3 := &result.X, &result.Y, &result.Z
var a, b, c, d, e, f FieldVal
z3.Mul2(y1, z1).MulInt(2) // Z3 = 2*Y1*Z1 (mag: 2)
a.SquareVal(x1) // A = X1^2 (mag: 1)
b.SquareVal(y1) // B = Y1^2 (mag: 1)
c.SquareVal(&b) // C = B^2 (mag: 1)
b.Add(x1).Square() // B = (X1+B)^2 (mag: 1)
d.Set(&a).Add(&c).Negate(2) // D = -(A+C) (mag: 3)
d.Add(&b).MulInt(2) // D = 2*(B+D)(mag: 8)
e.Set(&a).MulInt(3) // E = 3*A (mag: 3)
f.SquareVal(&e) // F = E^2 (mag: 1)
x3.Set(&d).MulInt(2).Negate(16) // X3 = -(2*D) (mag: 17)
x3.Add(&f) // X3 = F+X3 (mag: 18)
f.Set(x3).Negate(18).Add(&d).Normalize() // F = D-X3 (mag: 1)
y3.Set(&c).MulInt(8).Negate(8) // Y3 = -(8*C) (mag: 9)
y3.Add(f.Mul(&e)) // Y3 = E*F+Y3 (mag: 10)
// Normalize the field values back to a magnitude of 1.
x3.Normalize()
y3.Normalize()
z3.Normalize()
}
// DoubleNonConst doubles the passed Jacobian point and stores the result in the
// provided result parameter in *non-constant* time.
//
// NOTE: The point must be normalized for this function to return the correct
// result. The resulting point will be normalized.
func DoubleNonConst(p, result *JacobianPoint) {
// Doubling a point at infinity is still infinity.
if p.Y.IsZero() || p.Z.IsZero() {
result.X.SetInt(0)
result.Y.SetInt(0)
result.Z.SetInt(0)
return
}
// Slightly faster point doubling can be achieved when the z value is 1
// by avoiding the multiplication on the z value. This section calls
// a point doubling function which is accelerated by using that
// assumption when possible.
if p.Z.IsOne() {
doubleZ1EqualsOne(p, result)
return
}
// Fall back to generic point doubling which works with arbitrary z
// values.
doubleGeneric(p, result)
}
// splitK returns a balanced length-two representation of k and their signs.
// This is algorithm 3.74 from [GECC].
//
// One thing of note about this algorithm is that no matter what c1 and c2 are,
// the final equation of k = k1 + k2 * lambda (mod n) will hold. This is
// provable mathematically due to how a1/b1/a2/b2 are computed.
//
// c1 and c2 are chosen to minimize the max(k1,k2).
func splitK(k []byte) ([]byte, []byte, int, int) {
// All math here is done with big.Int, which is slow.
// At some point, it might be useful to write something similar to
// FieldVal but for N instead of P as the prime field if this ends up
// being a bottleneck.
bigIntK := new(big.Int)
c1, c2 := new(big.Int), new(big.Int)
tmp1, tmp2 := new(big.Int), new(big.Int)
k1, k2 := new(big.Int), new(big.Int)
bigIntK.SetBytes(k)
// c1 = round(b2 * k / n) from step 4.
// Rounding isn't really necessary and costs too much, hence skipped
c1.Mul(endomorphismB2, bigIntK)
c1.Div(c1, curveParams.N)
// c2 = round(b1 * k / n) from step 4 (sign reversed to optimize one step)
// Rounding isn't really necessary and costs too much, hence skipped
c2.Mul(endomorphismB1, bigIntK)
c2.Div(c2, curveParams.N)
// k1 = k - c1 * a1 - c2 * a2 from step 5 (note c2's sign is reversed)
tmp1.Mul(c1, endomorphismA1)
tmp2.Mul(c2, endomorphismA2)
k1.Sub(bigIntK, tmp1)
k1.Add(k1, tmp2)
// k2 = - c1 * b1 - c2 * b2 from step 5 (note c2's sign is reversed)
tmp1.Mul(c1, endomorphismB1)
tmp2.Mul(c2, endomorphismB2)
k2.Sub(tmp2, tmp1)
// Note Bytes() throws out the sign of k1 and k2. This matters
// since k1 and/or k2 can be negative. Hence, we pass that
// back separately.
return k1.Bytes(), k2.Bytes(), k1.Sign(), k2.Sign()
}
// nafScalar represents a positive integer up to a maximum value of 2^256 - 1
// encoded in non-adjacent form.
//
// NAF is a signed-digit representation where each digit can be +1, 0, or -1.
//
// In order to efficiently encode that information, this type uses two arrays, a
// "positive" array where set bits represent the +1 signed digits and a
// "negative" array where set bits represent the -1 signed digits. 0 is
// represented by neither array having a bit set in that position.
//
// The Pos and Neg methods return the aforementioned positive and negative
// arrays, respectively.
type nafScalar struct {
// pos houses the positive portion of the representation. An additional
// byte is required for the positive portion because the NAF encoding can be
// up to 1 bit longer than the normal binary encoding of the value.
//
// neg houses the negative portion of the representation. Even though the
// additional byte is not required for the negative portion, since it can
// never exceed the length of the normal binary encoding of the value,
// keeping the same length for positive and negative portions simplifies
// working with the representation and allows extra conditional branches to
// be avoided.
//
// start and end specify the starting and ending index to use within the pos
// and neg arrays, respectively. This allows fixed size arrays to be used
// versus needing to dynamically allocate space on the heap.
//
// NOTE: The fields are defined in the order that they are to minimize the
// padding on 32-bit and 64-bit platforms.
pos [33]byte
start, end uint8
neg [33]byte
}
// Pos returns the bytes of the encoded value with bits set in the positions
// that represent a signed digit of +1.
func (s *nafScalar) Pos() []byte {
return s.pos[s.start:s.end]
}
// Neg returns the bytes of the encoded value with bits set in the positions
// that represent a signed digit of -1.
func (s *nafScalar) Neg() []byte {
return s.neg[s.start:s.end]
}
// naf takes a positive integer up to a maximum value of 2^256 - 1 and returns
// its non-adjacent form (NAF), which is a unique signed-digit representation
// such that no two consecutive digits are nonzero. See the documentation for
// the returned type for details on how the representation is encoded
// efficiently and how to interpret it
//
// NAF is useful in that it has the fewest nonzero digits of any signed digit
// representation, only 1/3rd of its digits are nonzero on average, and at least
// half of the digits will be 0.
//
// The aforementioned properties are particularly beneficial for optimizing
// elliptic curve point multiplication because they effectively minimize the
// number of required point additions in exchange for needing to perform a mix
// of fewer point additions and subtractions and possibly one additional point
// doubling. This is an excellent tradeoff because subtraction of points has
// the same computational complexity as addition of points and point doubling is
// faster than both.
func naf(k []byte) nafScalar {
// Strip leading zero bytes.
for len(k) > 0 && k[0] == 0x00 {
k = k[1:]
}
// The non-adjacent form (NAF) of a positive integer k is an expression
// k = ∑_(i=0, l-1) k_i * 2^i where k_i ∈ {0,±1}, k_(l-1) != 0, and no two
// consecutive digits k_i are nonzero.
//
// The traditional method of computing the NAF of a positive integer is
// given by algorithm 3.30 in [GECC]. It consists of repeatedly dividing k
// by 2 and choosing the remainder so that the quotient (kr)/2 is even
// which ensures the next NAF digit is 0. This requires log_2(k) steps.
//
// However, in [BRID], Prodinger notes that a closed form expression for the
// NAF representation is the bitwise difference 3k/2 - k/2. This is more
// efficient as it can be computed in O(1) versus the O(log(n)) of the
// traditional approach.
//
// The following code makes use of that formula to compute the NAF more
// efficiently.
//
// To understand the logic here, observe that the only way the NAF has a
// nonzero digit at a given bit is when either 3k/2 or k/2 has a bit set in
// that position, but not both. In other words, the result of a bitwise
// xor. This can be seen simply by considering that when the bits are the
// same, the subtraction is either 0-0 or 1-1, both of which are 0.
//
// Further, observe that the "+1" digits in the result are contributed by
// 3k/2 while the "-1" digits are from k/2. So, they can be determined by
// taking the bitwise and of each respective value with the result of the
// xor which identifies which bits are nonzero.
//
// Using that information, this loops backwards from the least significant
// byte to the most significant byte while performing the aforementioned
// calculations by propagating the potential carry and high order bit from
// the next word during the right shift.
kLen := len(k)
var result nafScalar
var carry uint8
for byteNum := kLen - 1; byteNum >= 0; byteNum-- {
// Calculate k/2. Notice the carry from the previous word is added and
// the low order bit from the next word is shifted in accordingly.
kc := uint16(k[byteNum]) + uint16(carry)
var nextWord uint8
if byteNum > 0 {
nextWord = k[byteNum-1]
}
halfK := kc>>1 | uint16(nextWord<<7)
// Calculate 3k/2 and determine the non-zero digits in the result.
threeHalfK := kc + halfK
nonZeroResultDigits := threeHalfK ^ halfK
// Determine the signed digits {0, ±1}.
result.pos[byteNum+1] = uint8(threeHalfK & nonZeroResultDigits)
result.neg[byteNum+1] = uint8(halfK & nonZeroResultDigits)
// Propagate the potential carry from the 3k/2 calculation.
carry = uint8(threeHalfK >> 8)
}
result.pos[0] = carry
// Set the starting and ending positions within the fixed size arrays to
// identify the bytes that are actually used. This is important since the
// encoding is big endian and thus trailing zero bytes changes its value.
result.start = 1 - carry
result.end = uint8(kLen + 1)
return result
}
// ScalarMultNonConst multiplies k*P where k is a big endian integer modulo the
// curve order and P is a point in Jacobian projective coordinates and stores
// the result in the provided Jacobian point.
//
// NOTE: The point must be normalized for this function to return the correct
// result. The resulting point will be normalized.
func ScalarMultNonConst(k *ModNScalar, point, result *JacobianPoint) {
// Decompose K into k1 and k2 in order to halve the number of EC ops.
// See Algorithm 3.74 in [GECC].
kBytes := k.Bytes()
k1, k2, signK1, signK2 := splitK(kBytes[:])
zeroArray32(&kBytes)
// The main equation here to remember is:
// k * P = k1 * P + k2 * ϕ(P)
//
// P1 below is P in the equation, P2 below is ϕ(P) in the equation
p1, p1Neg := new(JacobianPoint), new(JacobianPoint)
p1.Set(point)
p1Neg.Set(p1)
p1Neg.Y.Negate(1).Normalize()
// NOTE: ϕ(x,y) = (βx,y). The Jacobian z coordinates are the same, so this
// math goes through.
p2, p2Neg := new(JacobianPoint), new(JacobianPoint)
p2.Set(p1)
p2.X.Mul(endomorphismBeta).Normalize()
p2Neg.Set(p2)
p2Neg.Y.Negate(1).Normalize()
// Flip the positive and negative values of the points as needed
// depending on the signs of k1 and k2. As mentioned in the equation
// above, each of k1 and k2 are multiplied by the respective point.
// Since -k * P is the same thing as k * -P, and the group law for
// elliptic curves states that P(x, y) = -P(x, -y), it's faster and
// simplifies the code to just make the point negative.
if signK1 == -1 {
p1, p1Neg = p1Neg, p1
}
if signK2 == -1 {
p2, p2Neg = p2Neg, p2
}
// NAF versions of k1 and k2 should have a lot more zeros.
//
// The Pos version of the bytes contain the +1s and the Neg versions
// contain the -1s.
k1NAF, k2NAF := naf(k1), naf(k2)
k1PosNAF, k1NegNAF := k1NAF.Pos(), k1NAF.Neg()
k2PosNAF, k2NegNAF := k2NAF.Pos(), k2NAF.Neg()
k1Len, k2Len := len(k1PosNAF), len(k2PosNAF)
m := k1Len
if m < k2Len {
m = k2Len
}
// Point Q = ∞ (point at infinity).
var q JacobianPoint
// Add left-to-right using the NAF optimization. See algorithm 3.77
// from [GECC]. This should be faster overall since there will be a lot
// more instances of 0, hence reducing the number of Jacobian additions
// at the cost of 1 possible extra doubling.
for i := 0; i < m; i++ {
// Since k1 and k2 are potentially different lengths and the calculation
// is being done left to right, pad the front of the shorter one with
// 0s.
var k1BytePos, k1ByteNeg, k2BytePos, k2ByteNeg byte
if i >= m-k1Len {
k1BytePos, k1ByteNeg = k1PosNAF[i-(m-k1Len)], k1NegNAF[i-(m-k1Len)]
}
if i >= m-k2Len {
k2BytePos, k2ByteNeg = k2PosNAF[i-(m-k2Len)], k2NegNAF[i-(m-k2Len)]
}
for bit, mask := 7, uint8(1<<7); bit >= 0; bit, mask = bit-1, mask>>1 {
// Q = 2 * Q
DoubleNonConst(&q, &q)
// Add or subtract the first point based on the signed digit of the
// NAF representation of k1 at this bit position.
//
// +1: Q = Q + p1
// -1: Q = Q - p1
// 0: Q = Q (no change)
if k1BytePos&mask == mask {
AddNonConst(&q, p1, &q)
} else if k1ByteNeg&mask == mask {
AddNonConst(&q, p1Neg, &q)
}
// Add or subtract the second point based on the signed digit of the
// NAF representation of k2 at this bit position.
//
// +1: Q = Q + p2
// -1: Q = Q - p2
// 0: Q = Q (no change)
if k2BytePos&mask == mask {
AddNonConst(&q, p2, &q)
} else if k2ByteNeg&mask == mask {
AddNonConst(&q, p2Neg, &q)
}
}
}
result.Set(&q)
}
// ScalarBaseMultNonConst multiplies k*G where G is the base point of the group
// and k is a big endian integer. The result is stored in Jacobian coordinates
// (x1, y1, z1).
//
// NOTE: The resulting point will be normalized.
func ScalarBaseMultNonConst(k *ModNScalar, result *JacobianPoint) {
bytePoints := s256BytePoints()
// Point Q = ∞ (point at infinity).
var q JacobianPoint
// curve.bytePoints has all 256 byte points for each 8-bit window. The
// strategy is to add up the byte points. This is best understood by
// expressing k in base-256 which it already sort of is. Each "digit" in
// the 8-bit window can be looked up using bytePoints and added together.
var pt JacobianPoint
for i, byteVal := range k.Bytes() {
p := bytePoints[i][byteVal]
pt.X.Set(&p[0])
pt.Y.Set(&p[1])
pt.Z.SetInt(1)
AddNonConst(&q, &pt, &q)
}
result.Set(&q)
}
// isOnCurve returns whether or not the affine point (x,y) is on the curve.
func isOnCurve(fx, fy *FieldVal) bool {
// Elliptic curve equation for secp256k1 is: y^2 = x^3 + 7
y2 := new(FieldVal).SquareVal(fy).Normalize()
result := new(FieldVal).SquareVal(fx).Mul(fx).AddInt(7).Normalize()
return y2.Equals(result)
}
// DecompressY attempts to calculate the Y coordinate for the given X coordinate
// such that the result pair is a point on the secp256k1 curve. It adjusts Y
// based on the desired oddness and returns whether or not it was successful
// since not all X coordinates are valid.
//
// The magnitude of the provided X coordinate field val must be a max of 8 for a
// correct result. The resulting Y field val will have a max magnitude of 2.
func DecompressY(x *FieldVal, odd bool, resultY *FieldVal) bool {
// The curve equation for secp256k1 is: y^2 = x^3 + 7. Thus
// y = +-sqrt(x^3 + 7).
//
// The x coordinate must be invalid if there is no square root for the
// calculated rhs because it means the X coordinate is not for a point on
// the curve.
x3PlusB := new(FieldVal).SquareVal(x).Mul(x).AddInt(7)
if hasSqrt := resultY.SquareRootVal(x3PlusB); !hasSqrt {
return false
}
if resultY.Normalize().IsOdd() != odd {
resultY.Negate(1)
}
return true
}

View File

@ -0,0 +1,58 @@
// Copyright (c) 2013-2014 The btcsuite developers
// Copyright (c) 2015-2019 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
/*
Package secp256k1 implements optimized secp256k1 elliptic curve operations.
This package provides an optimized pure Go implementation of elliptic curve
cryptography operations over the secp256k1 curve as well as data structures and
functions for working with public and private secp256k1 keys. See
https://www.secg.org/sec2-v2.pdf for details on the standard.
In addition, sub packages are provided to produce, verify, parse, and serialize
ECDSA signatures and EC-Schnorr-DCRv0 (a custom Schnorr-based signature scheme
specific to Decred) signatures. See the README.md files in the relevant sub
packages for more details about those aspects.
An overview of the features provided by this package are as follows:
- Private key generation, serialization, and parsing
- Public key generation, serialization and parsing per ANSI X9.62-1998
- Parses uncompressed, compressed, and hybrid public keys
- Serializes uncompressed and compressed public keys
- Specialized types for performing optimized and constant time field operations
- FieldVal type for working modulo the secp256k1 field prime
- ModNScalar type for working modulo the secp256k1 group order
- Elliptic curve operations in Jacobian projective coordinates
- Point addition
- Point doubling
- Scalar multiplication with an arbitrary point
- Scalar multiplication with the base point (group generator)
- Point decompression from a given x coordinate
- Nonce generation via RFC6979 with support for extra data and version
information that can be used to prevent nonce reuse between signing
algorithms
It also provides an implementation of the Go standard library crypto/elliptic
Curve interface via the S256 function so that it may be used with other packages
in the standard library such as crypto/tls, crypto/x509, and crypto/ecdsa.
However, in the case of ECDSA, it is highly recommended to use the ecdsa sub
package of this package instead since it is optimized specifically for secp256k1
and is significantly faster as a result.
Although this package was primarily written for dcrd, it has intentionally been
designed so it can be used as a standalone package for any projects needing to
use optimized secp256k1 elliptic curve cryptography.
Finally, a comprehensive suite of tests is provided to provide a high level of
quality assurance.
Use of secp256k1 in Decred
At the time of this writing, the primary public key cryptography in widespread
use on the Decred network used to secure coins is based on elliptic curves
defined by the secp256k1 domain parameters.
*/
package secp256k1

View File

@ -0,0 +1,21 @@
// Copyright (c) 2015 The btcsuite developers
// Copyright (c) 2015-2016 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package secp256k1
// GenerateSharedSecret generates a shared secret based on a private key and a
// public key using Diffie-Hellman key exchange (ECDH) (RFC 5903).
// RFC5903 Section 9 states we should only return x.
//
// It is recommended to securily hash the result before using as a cryptographic
// key.
func GenerateSharedSecret(privkey *PrivateKey, pubkey *PublicKey) []byte {
var point, result JacobianPoint
pubkey.AsJacobian(&point)
ScalarMultNonConst(&privkey.Key, &point, &result)
result.ToAffine()
xBytes := result.X.Bytes()
return xBytes[:]
}

View File

@ -0,0 +1,52 @@
ecdsa
=====
[![Build Status](https://github.com/decred/dcrd/workflows/Build%20and%20Test/badge.svg)](https://github.com/decred/dcrd/actions)
[![ISC License](https://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](https://pkg.go.dev/github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa)
Package ecdsa provides secp256k1-optimized ECDSA signing and verification.
This package provides data structures and functions necessary to produce and
verify deterministic canonical signatures in accordance with RFC6979 and
BIP0062, optimized specifically for the secp256k1 curve using the Elliptic Curve
Digital Signature Algorithm (ECDSA), as defined in FIPS 186-3. See
https://www.secg.org/sec2-v2.pdf for details on the secp256k1 standard.
It also provides functions to parse and serialize the ECDSA signatures with the
more strict Distinguished Encoding Rules (DER) of ISO/IEC 8825-1 and some
additional restrictions specific to secp256k1.
In addition, it supports a custom "compact" signature format which allows
efficient recovery of the public key from a given valid signature and message
hash combination.
A comprehensive suite of tests is provided to ensure proper functionality.
## ECDSA use in Decred
At the time of this writing, ECDSA signatures are heavily used for proving coin
ownership in Decred as the vast majority of transactions consist of what is
effectively transferring ownership of coins to a public key associated with a
private key only known to the recipient of the coins along with an encumbrance
that requires an ECDSA signature that proves the new owner possesses the private
key without actually revealing it.
## Installation and Updating
This package is part of the `github.com/decred/dcrd/dcrec/secp256k1/v4` module.
Use the standard go tooling for working with modules to incorporate it.
## Examples
* [Sign Message](https://pkg.go.dev/github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa#example-package-SignMessage)
Demonstrates signing a message with a secp256k1 private key that is first
parsed from raw bytes and serializing the generated signature.
* [Verify Signature](https://pkg.go.dev/github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa#example-Signature.Verify)
Demonstrates verifying a secp256k1 signature against a public key that is
first parsed from raw bytes. The signature is also parsed from raw bytes.
## License
Package ecdsa is licensed under the [copyfree](http://copyfree.org) ISC License.

View File

@ -0,0 +1,42 @@
// Copyright (c) 2020 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
/*
Package ecdsa provides secp256k1-optimized ECDSA signing and verification.
This package provides data structures and functions necessary to produce and
verify deterministic canonical signatures in accordance with RFC6979 and
BIP0062, optimized specifically for the secp256k1 curve using the Elliptic Curve
Digital Signature Algorithm (ECDSA), as defined in FIPS 186-3. See
https://www.secg.org/sec2-v2.pdf for details on the secp256k1 standard.
It also provides functions to parse and serialize the ECDSA signatures with the
more strict Distinguished Encoding Rules (DER) of ISO/IEC 8825-1 and some
additional restrictions specific to secp256k1.
In addition, it supports a custom "compact" signature format which allows
efficient recovery of the public key from a given valid signature and message
hash combination.
A comprehensive suite of tests is provided to ensure proper functionality.
ECDSA use in Decred
At the time of this writing, ECDSA signatures are heavily used for proving coin
ownership in Decred as the vast majority of transactions consist of what is
effectively transferring ownership of coins to a public key associated with a
private key only known to the recipient of the coins along with an encumbrance
that requires an ECDSA signature that proves the new owner possesses the private
key without actually revealing it.
Errors
Errors returned by this package are of type ecdsa.Error and fully support the
standard library errors.Is and errors.As functions. This allows the caller to
programmatically determine the specific error by examining the ErrorKind field
of the type asserted ecdsa.Error while still providing rich error messages with
contextual information. See ErrorKind in the package documentation for a full
list.
*/
package ecdsa

View File

@ -0,0 +1,116 @@
// Copyright (c) 2020 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package ecdsa
// ErrorKind identifies a kind of error. It has full support for
// errors.Is and errors.As, so the caller can directly check against
// an error kind when determining the reason for an error.
type ErrorKind string
// These constants are used to identify a specific Error.
const (
// ErrSigTooShort is returned when a signature that should be a DER
// signature is too short.
ErrSigTooShort = ErrorKind("ErrSigTooShort")
// ErrSigTooLong is returned when a signature that should be a DER signature
// is too long.
ErrSigTooLong = ErrorKind("ErrSigTooLong")
// ErrSigInvalidSeqID is returned when a signature that should be a DER
// signature does not have the expected ASN.1 sequence ID.
ErrSigInvalidSeqID = ErrorKind("ErrSigInvalidSeqID")
// ErrSigInvalidDataLen is returned when a signature that should be a DER
// signature does not specify the correct number of remaining bytes for the
// R and S portions.
ErrSigInvalidDataLen = ErrorKind("ErrSigInvalidDataLen")
// ErrSigMissingSTypeID is returned when a signature that should be a DER
// signature does not provide the ASN.1 type ID for S.
ErrSigMissingSTypeID = ErrorKind("ErrSigMissingSTypeID")
// ErrSigMissingSLen is returned when a signature that should be a DER
// signature does not provide the length of S.
ErrSigMissingSLen = ErrorKind("ErrSigMissingSLen")
// ErrSigInvalidSLen is returned when a signature that should be a DER
// signature does not specify the correct number of bytes for the S portion.
ErrSigInvalidSLen = ErrorKind("ErrSigInvalidSLen")
// ErrSigInvalidRIntID is returned when a signature that should be a DER
// signature does not have the expected ASN.1 integer ID for R.
ErrSigInvalidRIntID = ErrorKind("ErrSigInvalidRIntID")
// ErrSigZeroRLen is returned when a signature that should be a DER
// signature has an R length of zero.
ErrSigZeroRLen = ErrorKind("ErrSigZeroRLen")
// ErrSigNegativeR is returned when a signature that should be a DER
// signature has a negative value for R.
ErrSigNegativeR = ErrorKind("ErrSigNegativeR")
// ErrSigTooMuchRPadding is returned when a signature that should be a DER
// signature has too much padding for R.
ErrSigTooMuchRPadding = ErrorKind("ErrSigTooMuchRPadding")
// ErrSigRIsZero is returned when a signature has R set to the value zero.
ErrSigRIsZero = ErrorKind("ErrSigRIsZero")
// ErrSigRTooBig is returned when a signature has R with a value that is
// greater than or equal to the group order.
ErrSigRTooBig = ErrorKind("ErrSigRTooBig")
// ErrSigInvalidSIntID is returned when a signature that should be a DER
// signature does not have the expected ASN.1 integer ID for S.
ErrSigInvalidSIntID = ErrorKind("ErrSigInvalidSIntID")
// ErrSigZeroSLen is returned when a signature that should be a DER
// signature has an S length of zero.
ErrSigZeroSLen = ErrorKind("ErrSigZeroSLen")
// ErrSigNegativeS is returned when a signature that should be a DER
// signature has a negative value for S.
ErrSigNegativeS = ErrorKind("ErrSigNegativeS")
// ErrSigTooMuchSPadding is returned when a signature that should be a DER
// signature has too much padding for S.
ErrSigTooMuchSPadding = ErrorKind("ErrSigTooMuchSPadding")
// ErrSigSIsZero is returned when a signature has S set to the value zero.
ErrSigSIsZero = ErrorKind("ErrSigSIsZero")
// ErrSigSTooBig is returned when a signature has S with a value that is
// greater than or equal to the group order.
ErrSigSTooBig = ErrorKind("ErrSigSTooBig")
)
// Error satisfies the error interface and prints human-readable errors.
func (e ErrorKind) Error() string {
return string(e)
}
// Error identifies an error related to an ECDSA signature. It has full
// support for errors.Is and errors.As, so the caller can ascertain the
// specific reason for the error by checking the underlying error.
type Error struct {
Err error
Description string
}
// Error satisfies the error interface and prints human-readable errors.
func (e Error) Error() string {
return e.Description
}
// Unwrap returns the underlying wrapped error.
func (e Error) Unwrap() error {
return e.Err
}
// signatureError creates an Error given a set of arguments.
func signatureError(kind ErrorKind, desc string) Error {
return Error{Err: kind, Description: desc}
}

View File

@ -0,0 +1,925 @@
// Copyright (c) 2013-2014 The btcsuite developers
// Copyright (c) 2015-2020 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package ecdsa
import (
"errors"
"fmt"
"github.com/decred/dcrd/dcrec/secp256k1/v4"
)
// References:
// [GECC]: Guide to Elliptic Curve Cryptography (Hankerson, Menezes, Vanstone)
//
// [ISO/IEC 8825-1]: Information technology — ASN.1 encoding rules:
// Specification of Basic Encoding Rules (BER), Canonical Encoding Rules
// (CER) and Distinguished Encoding Rules (DER)
//
// [SEC1]: Elliptic Curve Cryptography (May 31, 2009, Version 2.0)
// https://www.secg.org/sec1-v2.pdf
var (
// zero32 is an array of 32 bytes used for the purposes of zeroing and is
// defined here to avoid extra allocations.
zero32 = [32]byte{}
// orderAsFieldVal is the order of the secp256k1 curve group stored as a
// field value. It is provided here to avoid the need to create it multiple
// times.
orderAsFieldVal = func() *secp256k1.FieldVal {
var f secp256k1.FieldVal
f.SetByteSlice(secp256k1.Params().N.Bytes())
return &f
}()
)
const (
// asn1SequenceID is the ASN.1 identifier for a sequence and is used when
// parsing and serializing signatures encoded with the Distinguished
// Encoding Rules (DER) format per section 10 of [ISO/IEC 8825-1].
asn1SequenceID = 0x30
// asn1IntegerID is the ASN.1 identifier for an integer and is used when
// parsing and serializing signatures encoded with the Distinguished
// Encoding Rules (DER) format per section 10 of [ISO/IEC 8825-1].
asn1IntegerID = 0x02
)
// Signature is a type representing an ECDSA signature.
type Signature struct {
r secp256k1.ModNScalar
s secp256k1.ModNScalar
}
// NewSignature instantiates a new signature given some r and s values.
func NewSignature(r, s *secp256k1.ModNScalar) *Signature {
return &Signature{*r, *s}
}
// Serialize returns the ECDSA signature in the Distinguished Encoding Rules
// (DER) format per section 10 of [ISO/IEC 8825-1] and such that the S component
// of the signature is less than or equal to the half order of the group.
//
// Note that the serialized bytes returned do not include the appended hash type
// used in Decred signature scripts.
func (sig *Signature) Serialize() []byte {
// The format of a DER encoded signature is as follows:
//
// 0x30 <total length> 0x02 <length of R> <R> 0x02 <length of S> <S>
// - 0x30 is the ASN.1 identifier for a sequence.
// - Total length is 1 byte and specifies length of all remaining data.
// - 0x02 is the ASN.1 identifier that specifies an integer follows.
// - Length of R is 1 byte and specifies how many bytes R occupies.
// - R is the arbitrary length big-endian encoded number which
// represents the R value of the signature. DER encoding dictates
// that the value must be encoded using the minimum possible number
// of bytes. This implies the first byte can only be null if the
// highest bit of the next byte is set in order to prevent it from
// being interpreted as a negative number.
// - 0x02 is once again the ASN.1 integer identifier.
// - Length of S is 1 byte and specifies how many bytes S occupies.
// - S is the arbitrary length big-endian encoded number which
// represents the S value of the signature. The encoding rules are
// identical as those for R.
// Ensure the S component of the signature is less than or equal to the half
// order of the group because both S and its negation are valid signatures
// modulo the order, so this forces a consistent choice to reduce signature
// malleability.
sigS := new(secp256k1.ModNScalar).Set(&sig.s)
if sigS.IsOverHalfOrder() {
sigS.Negate()
}
// Serialize the R and S components of the signature into their fixed
// 32-byte big-endian encoding. Note that the extra leading zero byte is
// used to ensure it is canonical per DER and will be stripped if needed
// below.
var rBuf, sBuf [33]byte
sig.r.PutBytesUnchecked(rBuf[1:33])
sigS.PutBytesUnchecked(sBuf[1:33])
// Ensure the encoded bytes for the R and S components are canonical per DER
// by trimming all leading zero bytes so long as the next byte does not have
// the high bit set and it's not the final byte.
canonR, canonS := rBuf[:], sBuf[:]
for len(canonR) > 1 && canonR[0] == 0x00 && canonR[1]&0x80 == 0 {
canonR = canonR[1:]
}
for len(canonS) > 1 && canonS[0] == 0x00 && canonS[1]&0x80 == 0 {
canonS = canonS[1:]
}
// Total length of returned signature is 1 byte for each magic and length
// (6 total), plus lengths of R and S.
totalLen := 6 + len(canonR) + len(canonS)
b := make([]byte, 0, totalLen)
b = append(b, asn1SequenceID)
b = append(b, byte(totalLen-2))
b = append(b, asn1IntegerID)
b = append(b, byte(len(canonR)))
b = append(b, canonR...)
b = append(b, asn1IntegerID)
b = append(b, byte(len(canonS)))
b = append(b, canonS...)
return b
}
// zeroArray32 zeroes the provided 32-byte buffer.
func zeroArray32(b *[32]byte) {
copy(b[:], zero32[:])
}
// fieldToModNScalar converts a field value to scalar modulo the group order and
// returns the scalar along with either 1 if it was reduced (aka it overflowed)
// or 0 otherwise.
//
// Note that a bool is not used here because it is not possible in Go to convert
// from a bool to numeric value in constant time and many constant-time
// operations require a numeric value.
func fieldToModNScalar(v *secp256k1.FieldVal) (secp256k1.ModNScalar, uint32) {
var buf [32]byte
v.PutBytes(&buf)
var s secp256k1.ModNScalar
overflow := s.SetBytes(&buf)
zeroArray32(&buf)
return s, overflow
}
// modNScalarToField converts a scalar modulo the group order to a field value.
func modNScalarToField(v *secp256k1.ModNScalar) secp256k1.FieldVal {
var buf [32]byte
v.PutBytes(&buf)
var fv secp256k1.FieldVal
fv.SetBytes(&buf)
return fv
}
// Verify returns whether or not the signature is valid for the provided hash
// and secp256k1 public key.
func (sig *Signature) Verify(hash []byte, pubKey *secp256k1.PublicKey) bool {
// The algorithm for verifying an ECDSA signature is given as algorithm 4.30
// in [GECC].
//
// The following is a paraphrased version for reference:
//
// G = curve generator
// N = curve order
// Q = public key
// m = message
// R, S = signature
//
// 1. Fail if R and S are not in [1, N-1]
// 2. e = H(m)
// 3. w = S^-1 mod N
// 4. u1 = e * w mod N
// u2 = R * w mod N
// 5. X = u1G + u2Q
// 6. Fail if X is the point at infinity
// 7. x = X.x mod N (X.x is the x coordinate of X)
// 8. Verified if x == R
//
// However, since all group operations are done internally in Jacobian
// projective space, the algorithm is modified slightly here in order to
// avoid an expensive inversion back into affine coordinates at step 7.
// Credits to Greg Maxwell for originally suggesting this optimization.
//
// Ordinarily, step 7 involves converting the x coordinate to affine by
// calculating x = x / z^2 (mod P) and then calculating the remainder as
// x = x (mod N). Then step 8 compares it to R.
//
// Note that since R is the x coordinate mod N from a random point that was
// originally mod P, and the cofactor of the secp256k1 curve is 1, there are
// only two possible x coordinates that the original random point could have
// been to produce R: x, where x < N, and x+N, where x+N < P.
//
// This implies that the signature is valid if either:
// a) R == X.x / X.z^2 (mod P)
// => R * X.z^2 == X.x (mod P)
// --or--
// b) R + N < P && R + N == X.x / X.z^2 (mod P)
// => R + N < P && (R + N) * X.z^2 == X.x (mod P)
//
// Therefore the following modified algorithm is used:
//
// 1. Fail if R and S are not in [1, N-1]
// 2. e = H(m)
// 3. w = S^-1 mod N
// 4. u1 = e * w mod N
// u2 = R * w mod N
// 5. X = u1G + u2Q
// 6. Fail if X is the point at infinity
// 7. z = (X.z)^2 mod P (X.z is the z coordinate of X)
// 8. Verified if R * z == X.x (mod P)
// 9. Fail if R + N >= P
// 10. Verified if (R + N) * z == X.x (mod P)
// Step 1.
//
// Fail if R and S are not in [1, N-1].
if sig.r.IsZero() || sig.s.IsZero() {
return false
}
// Step 2.
//
// e = H(m)
var e secp256k1.ModNScalar
e.SetByteSlice(hash)
// Step 3.
//
// w = S^-1 mod N
w := new(secp256k1.ModNScalar).InverseValNonConst(&sig.s)
// Step 4.
//
// u1 = e * w mod N
// u2 = R * w mod N
u1 := new(secp256k1.ModNScalar).Mul2(&e, w)
u2 := new(secp256k1.ModNScalar).Mul2(&sig.r, w)
// Step 5.
//
// X = u1G + u2Q
var X, Q, u1G, u2Q secp256k1.JacobianPoint
pubKey.AsJacobian(&Q)
secp256k1.ScalarBaseMultNonConst(u1, &u1G)
secp256k1.ScalarMultNonConst(u2, &Q, &u2Q)
secp256k1.AddNonConst(&u1G, &u2Q, &X)
// Step 6.
//
// Fail if X is the point at infinity
if (X.X.IsZero() && X.Y.IsZero()) || X.Z.IsZero() {
return false
}
// Step 7.
//
// z = (X.z)^2 mod P (X.z is the z coordinate of X)
z := new(secp256k1.FieldVal).SquareVal(&X.Z)
// Step 8.
//
// Verified if R * z == X.x (mod P)
sigRModP := modNScalarToField(&sig.r)
result := new(secp256k1.FieldVal).Mul2(&sigRModP, z).Normalize()
if result.Equals(&X.X) {
return true
}
// Step 9.
//
// Fail if R + N >= P
if sigRModP.IsGtOrEqPrimeMinusOrder() {
return false
}
// Step 10.
//
// Verified if (R + N) * z == X.x (mod P)
sigRModP.Add(orderAsFieldVal)
result.Mul2(&sigRModP, z).Normalize()
return result.Equals(&X.X)
}
// IsEqual compares this Signature instance to the one passed, returning true if
// both Signatures are equivalent. A signature is equivalent to another, if
// they both have the same scalar value for R and S.
func (sig *Signature) IsEqual(otherSig *Signature) bool {
return sig.r.Equals(&otherSig.r) && sig.s.Equals(&otherSig.s)
}
// ParseDERSignature parses a signature in the Distinguished Encoding Rules
// (DER) format per section 10 of [ISO/IEC 8825-1] and enforces the following
// additional restrictions specific to secp256k1:
//
// - The R and S values must be in the valid range for secp256k1 scalars:
// - Negative values are rejected
// - Zero is rejected
// - Values greater than or equal to the secp256k1 group order are rejected
func ParseDERSignature(sig []byte) (*Signature, error) {
// The format of a DER encoded signature for secp256k1 is as follows:
//
// 0x30 <total length> 0x02 <length of R> <R> 0x02 <length of S> <S>
// - 0x30 is the ASN.1 identifier for a sequence
// - Total length is 1 byte and specifies length of all remaining data
// - 0x02 is the ASN.1 identifier that specifies an integer follows
// - Length of R is 1 byte and specifies how many bytes R occupies
// - R is the arbitrary length big-endian encoded number which
// represents the R value of the signature. DER encoding dictates
// that the value must be encoded using the minimum possible number
// of bytes. This implies the first byte can only be null if the
// highest bit of the next byte is set in order to prevent it from
// being interpreted as a negative number.
// - 0x02 is once again the ASN.1 integer identifier
// - Length of S is 1 byte and specifies how many bytes S occupies
// - S is the arbitrary length big-endian encoded number which
// represents the S value of the signature. The encoding rules are
// identical as those for R.
//
// NOTE: The DER specification supports specifying lengths that can occupy
// more than 1 byte, however, since this is specific to secp256k1
// signatures, all lengths will be a single byte.
const (
// minSigLen is the minimum length of a DER encoded signature and is
// when both R and S are 1 byte each.
//
// 0x30 + <1-byte> + 0x02 + 0x01 + <byte> + 0x2 + 0x01 + <byte>
minSigLen = 8
// maxSigLen is the maximum length of a DER encoded signature and is
// when both R and S are 33 bytes each. It is 33 bytes because a
// 256-bit integer requires 32 bytes and an additional leading null byte
// might be required if the high bit is set in the value.
//
// 0x30 + <1-byte> + 0x02 + 0x21 + <33 bytes> + 0x2 + 0x21 + <33 bytes>
maxSigLen = 72
// sequenceOffset is the byte offset within the signature of the
// expected ASN.1 sequence identifier.
sequenceOffset = 0
// dataLenOffset is the byte offset within the signature of the expected
// total length of all remaining data in the signature.
dataLenOffset = 1
// rTypeOffset is the byte offset within the signature of the ASN.1
// identifier for R and is expected to indicate an ASN.1 integer.
rTypeOffset = 2
// rLenOffset is the byte offset within the signature of the length of
// R.
rLenOffset = 3
// rOffset is the byte offset within the signature of R.
rOffset = 4
)
// The signature must adhere to the minimum and maximum allowed length.
sigLen := len(sig)
if sigLen < minSigLen {
str := fmt.Sprintf("malformed signature: too short: %d < %d", sigLen,
minSigLen)
return nil, signatureError(ErrSigTooShort, str)
}
if sigLen > maxSigLen {
str := fmt.Sprintf("malformed signature: too long: %d > %d", sigLen,
maxSigLen)
return nil, signatureError(ErrSigTooLong, str)
}
// The signature must start with the ASN.1 sequence identifier.
if sig[sequenceOffset] != asn1SequenceID {
str := fmt.Sprintf("malformed signature: format has wrong type: %#x",
sig[sequenceOffset])
return nil, signatureError(ErrSigInvalidSeqID, str)
}
// The signature must indicate the correct amount of data for all elements
// related to R and S.
if int(sig[dataLenOffset]) != sigLen-2 {
str := fmt.Sprintf("malformed signature: bad length: %d != %d",
sig[dataLenOffset], sigLen-2)
return nil, signatureError(ErrSigInvalidDataLen, str)
}
// Calculate the offsets of the elements related to S and ensure S is inside
// the signature.
//
// rLen specifies the length of the big-endian encoded number which
// represents the R value of the signature.
//
// sTypeOffset is the offset of the ASN.1 identifier for S and, like its R
// counterpart, is expected to indicate an ASN.1 integer.
//
// sLenOffset and sOffset are the byte offsets within the signature of the
// length of S and S itself, respectively.
rLen := int(sig[rLenOffset])
sTypeOffset := rOffset + rLen
sLenOffset := sTypeOffset + 1
if sTypeOffset >= sigLen {
str := "malformed signature: S type indicator missing"
return nil, signatureError(ErrSigMissingSTypeID, str)
}
if sLenOffset >= sigLen {
str := "malformed signature: S length missing"
return nil, signatureError(ErrSigMissingSLen, str)
}
// The lengths of R and S must match the overall length of the signature.
//
// sLen specifies the length of the big-endian encoded number which
// represents the S value of the signature.
sOffset := sLenOffset + 1
sLen := int(sig[sLenOffset])
if sOffset+sLen != sigLen {
str := "malformed signature: invalid S length"
return nil, signatureError(ErrSigInvalidSLen, str)
}
// R elements must be ASN.1 integers.
if sig[rTypeOffset] != asn1IntegerID {
str := fmt.Sprintf("malformed signature: R integer marker: %#x != %#x",
sig[rTypeOffset], asn1IntegerID)
return nil, signatureError(ErrSigInvalidRIntID, str)
}
// Zero-length integers are not allowed for R.
if rLen == 0 {
str := "malformed signature: R length is zero"
return nil, signatureError(ErrSigZeroRLen, str)
}
// R must not be negative.
if sig[rOffset]&0x80 != 0 {
str := "malformed signature: R is negative"
return nil, signatureError(ErrSigNegativeR, str)
}
// Null bytes at the start of R are not allowed, unless R would otherwise be
// interpreted as a negative number.
if rLen > 1 && sig[rOffset] == 0x00 && sig[rOffset+1]&0x80 == 0 {
str := "malformed signature: R value has too much padding"
return nil, signatureError(ErrSigTooMuchRPadding, str)
}
// S elements must be ASN.1 integers.
if sig[sTypeOffset] != asn1IntegerID {
str := fmt.Sprintf("malformed signature: S integer marker: %#x != %#x",
sig[sTypeOffset], asn1IntegerID)
return nil, signatureError(ErrSigInvalidSIntID, str)
}
// Zero-length integers are not allowed for S.
if sLen == 0 {
str := "malformed signature: S length is zero"
return nil, signatureError(ErrSigZeroSLen, str)
}
// S must not be negative.
if sig[sOffset]&0x80 != 0 {
str := "malformed signature: S is negative"
return nil, signatureError(ErrSigNegativeS, str)
}
// Null bytes at the start of S are not allowed, unless S would otherwise be
// interpreted as a negative number.
if sLen > 1 && sig[sOffset] == 0x00 && sig[sOffset+1]&0x80 == 0 {
str := "malformed signature: S value has too much padding"
return nil, signatureError(ErrSigTooMuchSPadding, str)
}
// The signature is validly encoded per DER at this point, however, enforce
// additional restrictions to ensure R and S are in the range [1, N-1] since
// valid ECDSA signatures are required to be in that range per spec.
//
// Also note that while the overflow checks are required to make use of the
// specialized mod N scalar type, rejecting zero here is not strictly
// required because it is also checked when verifying the signature, but
// there really isn't a good reason not to fail early here on signatures
// that do not conform to the ECDSA spec.
// Strip leading zeroes from R.
rBytes := sig[rOffset : rOffset+rLen]
for len(rBytes) > 0 && rBytes[0] == 0x00 {
rBytes = rBytes[1:]
}
// R must be in the range [1, N-1]. Notice the check for the maximum number
// of bytes is required because SetByteSlice truncates as noted in its
// comment so it could otherwise fail to detect the overflow.
var r secp256k1.ModNScalar
if len(rBytes) > 32 {
str := "invalid signature: R is larger than 256 bits"
return nil, signatureError(ErrSigRTooBig, str)
}
if overflow := r.SetByteSlice(rBytes); overflow {
str := "invalid signature: R >= group order"
return nil, signatureError(ErrSigRTooBig, str)
}
if r.IsZero() {
str := "invalid signature: R is 0"
return nil, signatureError(ErrSigRIsZero, str)
}
// Strip leading zeroes from S.
sBytes := sig[sOffset : sOffset+sLen]
for len(sBytes) > 0 && sBytes[0] == 0x00 {
sBytes = sBytes[1:]
}
// S must be in the range [1, N-1]. Notice the check for the maximum number
// of bytes is required because SetByteSlice truncates as noted in its
// comment so it could otherwise fail to detect the overflow.
var s secp256k1.ModNScalar
if len(sBytes) > 32 {
str := "invalid signature: S is larger than 256 bits"
return nil, signatureError(ErrSigSTooBig, str)
}
if overflow := s.SetByteSlice(sBytes); overflow {
str := "invalid signature: S >= group order"
return nil, signatureError(ErrSigSTooBig, str)
}
if s.IsZero() {
str := "invalid signature: S is 0"
return nil, signatureError(ErrSigSIsZero, str)
}
// Create and return the signature.
return NewSignature(&r, &s), nil
}
// signRFC6979 generates a deterministic ECDSA signature according to RFC 6979
// and BIP 62 and returns it along with an additional public key recovery code
// for efficiently recovering the public key from the signature.
func signRFC6979(privKey *secp256k1.PrivateKey, hash []byte) (*Signature, byte) {
// The algorithm for producing an ECDSA signature is given as algorithm 4.29
// in [GECC].
//
// The following is a paraphrased version for reference:
//
// G = curve generator
// N = curve order
// d = private key
// m = message
// r, s = signature
//
// 1. Select random nonce k in [1, N-1]
// 2. Compute kG
// 3. r = kG.x mod N (kG.x is the x coordinate of the point kG)
// Repeat from step 1 if r = 0
// 4. e = H(m)
// 5. s = k^-1(e + dr) mod N
// Repeat from step 1 if s = 0
// 6. Return (r,s)
//
// This is slightly modified here to conform to RFC6979 and BIP 62 as
// follows:
//
// A. Instead of selecting a random nonce in step 1, use RFC6979 to generate
// a deterministic nonce in [1, N-1] parameterized by the private key,
// message being signed, and an iteration count for the repeat cases
// B. Negate s calculated in step 5 if it is > N/2
// This is done because both s and its negation are valid signatures
// modulo the curve order N, so it forces a consistent choice to reduce
// signature malleability
privKeyScalar := &privKey.Key
var privKeyBytes [32]byte
privKeyScalar.PutBytes(&privKeyBytes)
defer zeroArray32(&privKeyBytes)
for iteration := uint32(0); ; iteration++ {
// Step 1 with modification A.
//
// Generate a deterministic nonce in [1, N-1] parameterized by the
// private key, message being signed, and iteration count.
k := secp256k1.NonceRFC6979(privKeyBytes[:], hash, nil, nil, iteration)
// Step 2.
//
// Compute kG
//
// Note that the point must be in affine coordinates.
var kG secp256k1.JacobianPoint
secp256k1.ScalarBaseMultNonConst(k, &kG)
kG.ToAffine()
// Step 3.
//
// r = kG.x mod N
// Repeat from step 1 if r = 0
r, overflow := fieldToModNScalar(&kG.X)
if r.IsZero() {
k.Zero()
continue
}
// Since the secp256k1 curve has a cofactor of 1, when recovering a
// public key from an ECDSA signature over it, there are four possible
// candidates corresponding to the following cases:
//
// 1) The X coord of the random point is < N and its Y coord even
// 2) The X coord of the random point is < N and its Y coord is odd
// 3) The X coord of the random point is >= N and its Y coord is even
// 4) The X coord of the random point is >= N and its Y coord is odd
//
// Rather than forcing the recovery procedure to check all possible
// cases, this creates a recovery code that uniquely identifies which of
// the cases apply by making use of 2 bits. Bit 0 identifies the
// oddness case and Bit 1 identifies the overflow case (aka when the X
// coord >= N).
//
// It is also worth noting that making use of Hasse's theorem shows
// there are around log_2((p-n)/p) ~= -127.65 ~= 1 in 2^127 points where
// the X coordinate is >= N. It is not possible to calculate these
// points since that would require breaking the ECDLP, but, in practice
// this strongly implies with extremely high probability that there are
// only a few actual points for which this case is true.
pubKeyRecoveryCode := byte(overflow<<1) | byte(kG.Y.IsOddBit())
// Step 4.
//
// e = H(m)
//
// Note that this actually sets e = H(m) mod N which is correct since
// it is only used in step 5 which itself is mod N.
var e secp256k1.ModNScalar
e.SetByteSlice(hash)
// Step 5 with modification B.
//
// s = k^-1(e + dr) mod N
// Repeat from step 1 if s = 0
// s = -s if s > N/2
kInv := new(secp256k1.ModNScalar).InverseValNonConst(k)
k.Zero()
s := new(secp256k1.ModNScalar).Mul2(privKeyScalar, &r).Add(&e).Mul(kInv)
if s.IsZero() {
continue
}
if s.IsOverHalfOrder() {
s.Negate()
// Negating s corresponds to the random point that would have been
// generated by -k (mod N), which necessarily has the opposite
// oddness since N is prime, thus flip the pubkey recovery code
// oddness bit accordingly.
pubKeyRecoveryCode ^= 0x01
}
// Step 6.
//
// Return (r,s)
return NewSignature(&r, s), pubKeyRecoveryCode
}
}
// Sign generates an ECDSA signature over the secp256k1 curve for the provided
// hash (which should be the result of hashing a larger message) using the given
// private key. The produced signature is deterministic (same message and same
// key yield the same signature) and canonical in accordance with RFC6979 and
// BIP0062.
func Sign(key *secp256k1.PrivateKey, hash []byte) *Signature {
signature, _ := signRFC6979(key, hash)
return signature
}
const (
// compactSigSize is the size of a compact signature. It consists of a
// compact signature recovery code byte followed by the R and S components
// serialized as 32-byte big-endian values. 1+32*2 = 65.
// for the R and S components. 1+32+32=65.
compactSigSize = 65
// compactSigMagicOffset is a value used when creating the compact signature
// recovery code inherited from Bitcoin and has no meaning, but has been
// retained for compatibility. For historical purposes, it was originally
// picked to avoid a binary representation that would allow compact
// signatures to be mistaken for other components.
compactSigMagicOffset = 27
// compactSigCompPubKey is a value used when creating the compact signature
// recovery code to indicate the original public key was compressed.
compactSigCompPubKey = 4
// pubKeyRecoveryCodeOddnessBit specifies the bit that indicates the oddess
// of the Y coordinate of the random point calculated when creating a
// signature.
pubKeyRecoveryCodeOddnessBit = 1 << 0
// pubKeyRecoveryCodeOverflowBit specifies the bit that indicates the X
// coordinate of the random point calculated when creating a signature was
// >= N, where N is the order of the group.
pubKeyRecoveryCodeOverflowBit = 1 << 1
)
// SignCompact produces a compact ECDSA signature over the secp256k1 curve for
// the provided hash (which should be the result of hashing a larger message)
// using the given private key. The isCompressedKey parameter specifies if the
// produced signature should reference a compressed public key or not.
//
// Compact signature format:
// <1-byte compact sig recovery code><32-byte R><32-byte S>
//
// The compact sig recovery code is the value 27 + public key recovery code + 4
// if the compact signature was created with a compressed public key.
func SignCompact(key *secp256k1.PrivateKey, hash []byte, isCompressedKey bool) []byte {
// Create the signature and associated pubkey recovery code and calculate
// the compact signature recovery code.
sig, pubKeyRecoveryCode := signRFC6979(key, hash)
compactSigRecoveryCode := compactSigMagicOffset + pubKeyRecoveryCode
if isCompressedKey {
compactSigRecoveryCode += compactSigCompPubKey
}
// Output <compactSigRecoveryCode><32-byte R><32-byte S>.
var b [compactSigSize]byte
b[0] = compactSigRecoveryCode
sig.r.PutBytesUnchecked(b[1:33])
sig.s.PutBytesUnchecked(b[33:65])
return b[:]
}
// RecoverCompact attempts to recover the secp256k1 public key from the provided
// compact signature and message hash. It first verifies the signature, and, if
// the signature matches then the recovered public key will be returned as well
// as a boolean indicating whether or not the original key was compressed.
func RecoverCompact(signature, hash []byte) (*secp256k1.PublicKey, bool, error) {
// The following is very loosely based on the information and algorithm that
// describes recovering a public key from and ECDSA signature in section
// 4.1.6 of [SEC1].
//
// Given the following parameters:
//
// G = curve generator
// N = group order
// P = field prime
// Q = public key
// m = message
// e = hash of the message
// r, s = signature
// X = random point used when creating signature whose x coordinate is r
//
// The equation to recover a public key candidate from an ECDSA signature
// is:
// Q = r^-1(sX - eG).
//
// This can be verified by plugging it in for Q in the sig verification
// equation:
// X = s^-1(eG + rQ) (mod N)
// => s^-1(eG + r(r^-1(sX - eG))) (mod N)
// => s^-1(eG + sX - eG) (mod N)
// => s^-1(sX) (mod N)
// => X (mod N)
//
// However, note that since r is the x coordinate mod N from a random point
// that was originally mod P, and the cofactor of the secp256k1 curve is 1,
// there are four possible points that the original random point could have
// been to produce r: (r,y), (r,-y), (r+N,y), and (r+N,-y). At least 2 of
// those points will successfully verify, and all 4 will successfully verify
// when the original x coordinate was in the range [N+1, P-1], but in any
// case, only one of them corresponds to the original private key used.
//
// The method described by section 4.1.6 of [SEC1] to determine which one is
// the correct one involves calculating each possibility as a candidate
// public key and comparing the candidate to the authentic public key. It
// also hints that is is possible to generate the signature in a such a
// way that only one of the candidate public keys is viable.
//
// A more efficient approach that is specific to the secp256k1 curve is used
// here instead which is to produce a "pubkey recovery code" when signing
// that uniquely identifies which of the 4 possibilities is correct for the
// original random point and using that to recover the pubkey directly as
// follows:
//
// 1. Fail if r and s are not in [1, N-1]
// 2. Convert r to integer mod P
// 3. If pubkey recovery code overflow bit is set:
// 3.1 Fail if r + N >= P
// 3.2 r = r + N (mod P)
// 4. y = +sqrt(r^3 + 7) (mod P)
// 4.1 Fail if y does not exist
// 4.2 y = -y if needed to match pubkey recovery code oddness bit
// 5. X = (r, y)
// 6. e = H(m) mod N
// 7. w = r^-1 mod N
// 8. u1 = -(e * w) mod N
// u2 = s * w mod N
// 9. Q = u1G + u2X
// 10. Fail if Q is the point at infinity
// A compact signature consists of a recovery byte followed by the R and
// S components serialized as 32-byte big-endian values.
if len(signature) != compactSigSize {
return nil, false, errors.New("invalid compact signature size")
}
// Parse and validate the compact signature recovery code.
const (
minValidCode = compactSigMagicOffset
maxValidCode = compactSigMagicOffset + compactSigCompPubKey + 3
)
sigRecoveryCode := signature[0]
if sigRecoveryCode < minValidCode || sigRecoveryCode > maxValidCode {
return nil, false, errors.New("invalid compact signature recovery code")
}
sigRecoveryCode -= compactSigMagicOffset
wasCompressed := sigRecoveryCode&compactSigCompPubKey != 0
pubKeyRecoveryCode := sigRecoveryCode & 3
// Step 1.
//
// Parse and validate the R and S signature components.
//
// Fail if r and s are not in [1, N-1].
var r, s secp256k1.ModNScalar
if overflow := r.SetByteSlice(signature[1:33]); overflow {
return nil, false, errors.New("signature R is >= curve order")
}
if r.IsZero() {
return nil, false, errors.New("signature R is 0")
}
if overflow := s.SetByteSlice(signature[33:]); overflow {
return nil, false, errors.New("signature S is >= curve order")
}
if s.IsZero() {
return nil, false, errors.New("signature S is 0")
}
// Step 2.
//
// Convert r to integer mod P.
fieldR := modNScalarToField(&r)
// Step 3.
//
// If pubkey recovery code overflow bit is set:
if pubKeyRecoveryCode&pubKeyRecoveryCodeOverflowBit != 0 {
// Step 3.1.
//
// Fail if r + N >= P
//
// Either the signature or the recovery code must be invalid if the
// recovery code overflow bit is set and adding N to the R component
// would exceed the field prime since R originally came from the X
// coordinate of a random point on the curve.
if fieldR.IsGtOrEqPrimeMinusOrder() {
return nil, false, errors.New("signature R + N >= P")
}
// Step 3.2.
//
// r = r + N (mod P)
fieldR.Add(orderAsFieldVal)
}
// Step 4.
//
// y = +sqrt(r^3 + 7) (mod P)
// Fail if y does not exist.
// y = -y if needed to match pubkey recovery code oddness bit
//
// The signature must be invalid if the calculation fails because the X
// coord originally came from a random point on the curve which means there
// must be a Y coord that satisfies the equation for a valid signature.
oddY := pubKeyRecoveryCode&pubKeyRecoveryCodeOddnessBit != 0
var y secp256k1.FieldVal
if valid := secp256k1.DecompressY(&fieldR, oddY, &y); !valid {
return nil, false, errors.New("signature is not for a valid curve point")
}
// Step 5.
//
// X = (r, y)
var X secp256k1.JacobianPoint
X.X.Set(&fieldR)
X.Y.Set(&y)
X.Z.SetInt(1)
// Step 6.
//
// e = H(m) mod N
var e secp256k1.ModNScalar
e.SetByteSlice(hash)
// Step 7.
//
// w = r^-1 mod N
w := new(secp256k1.ModNScalar).InverseValNonConst(&r)
// Step 8.
//
// u1 = -(e * w) mod N
// u2 = s * w mod N
u1 := new(secp256k1.ModNScalar).Mul2(&e, w).Negate()
u2 := new(secp256k1.ModNScalar).Mul2(&s, w)
// Step 9.
//
// Q = u1G + u2X
var Q, u1G, u2X secp256k1.JacobianPoint
secp256k1.ScalarBaseMultNonConst(u1, &u1G)
secp256k1.ScalarMultNonConst(u2, &X, &u2X)
secp256k1.AddNonConst(&u1G, &u2X, &Q)
// Step 10.
//
// Fail if Q is the point at infinity.
//
// Either the signature or the pubkey recovery code must be invalid if the
// recovered pubkey is the point at infinity.
if (Q.X.IsZero() && Q.Y.IsZero()) || Q.Z.IsZero() {
return nil, false, errors.New("recovered pubkey is the point at infinity")
}
// Notice that the public key is in affine coordinates.
Q.ToAffine()
pubKey := secp256k1.NewPublicKey(&Q.X, &Q.Y)
return pubKey, wasCompressed, nil
}

View File

@ -0,0 +1,255 @@
// Copyright 2020-2021 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package secp256k1
// References:
// [SECG]: Recommended Elliptic Curve Domain Parameters
// https://www.secg.org/sec2-v2.pdf
//
// [GECC]: Guide to Elliptic Curve Cryptography (Hankerson, Menezes, Vanstone)
import (
"crypto/ecdsa"
"crypto/elliptic"
"math/big"
)
// CurveParams contains the parameters for the secp256k1 curve.
type CurveParams struct {
// P is the prime used in the secp256k1 field.
P *big.Int
// N is the order of the secp256k1 curve group generated by the base point.
N *big.Int
// Gx and Gy are the x and y coordinate of the base point, respectively.
Gx, Gy *big.Int
// BitSize is the size of the underlying secp256k1 field in bits.
BitSize int
// H is the cofactor of the secp256k1 curve.
H int
// ByteSize is simply the bit size / 8 and is provided for convenience
// since it is calculated repeatedly.
ByteSize int
}
// Curve parameters taken from [SECG] section 2.4.1.
var curveParams = CurveParams{
P: fromHex("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"),
N: fromHex("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"),
Gx: fromHex("79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"),
Gy: fromHex("483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"),
BitSize: 256,
H: 1,
ByteSize: 256 / 8,
}
// Params returns the secp256k1 curve parameters for convenience.
func Params() *CurveParams {
return &curveParams
}
// KoblitzCurve provides an implementation for secp256k1 that fits the ECC Curve
// interface from crypto/elliptic.
type KoblitzCurve struct {
*elliptic.CurveParams
}
// bigAffineToJacobian takes an affine point (x, y) as big integers and converts
// it to Jacobian point with Z=1.
func bigAffineToJacobian(x, y *big.Int, result *JacobianPoint) {
result.X.SetByteSlice(x.Bytes())
result.Y.SetByteSlice(y.Bytes())
result.Z.SetInt(1)
}
// jacobianToBigAffine takes a Jacobian point (x, y, z) as field values and
// converts it to an affine point as big integers.
func jacobianToBigAffine(point *JacobianPoint) (*big.Int, *big.Int) {
point.ToAffine()
// Convert the field values for the now affine point to big.Ints.
x3, y3 := new(big.Int), new(big.Int)
x3.SetBytes(point.X.Bytes()[:])
y3.SetBytes(point.Y.Bytes()[:])
return x3, y3
}
// Params returns the parameters for the curve.
//
// This is part of the elliptic.Curve interface implementation.
func (curve *KoblitzCurve) Params() *elliptic.CurveParams {
return curve.CurveParams
}
// IsOnCurve returns whether or not the affine point (x,y) is on the curve.
//
// This is part of the elliptic.Curve interface implementation. This function
// differs from the crypto/elliptic algorithm since a = 0 not -3.
func (curve *KoblitzCurve) IsOnCurve(x, y *big.Int) bool {
// Convert big ints to a Jacobian point for faster arithmetic.
var point JacobianPoint
bigAffineToJacobian(x, y, &point)
return isOnCurve(&point.X, &point.Y)
}
// Add returns the sum of (x1,y1) and (x2,y2).
//
// This is part of the elliptic.Curve interface implementation.
func (curve *KoblitzCurve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
// A point at infinity is the identity according to the group law for
// elliptic curve cryptography. Thus, ∞ + P = P and P + ∞ = P.
if x1.Sign() == 0 && y1.Sign() == 0 {
return x2, y2
}
if x2.Sign() == 0 && y2.Sign() == 0 {
return x1, y1
}
// Convert the affine coordinates from big integers to Jacobian points,
// do the point addition in Jacobian projective space, and convert the
// Jacobian point back to affine big.Ints.
var p1, p2, result JacobianPoint
bigAffineToJacobian(x1, y1, &p1)
bigAffineToJacobian(x2, y2, &p2)
AddNonConst(&p1, &p2, &result)
return jacobianToBigAffine(&result)
}
// Double returns 2*(x1,y1).
//
// This is part of the elliptic.Curve interface implementation.
func (curve *KoblitzCurve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) {
if y1.Sign() == 0 {
return new(big.Int), new(big.Int)
}
// Convert the affine coordinates from big integers to Jacobian points,
// do the point doubling in Jacobian projective space, and convert the
// Jacobian point back to affine big.Ints.
var point, result JacobianPoint
bigAffineToJacobian(x1, y1, &point)
DoubleNonConst(&point, &result)
return jacobianToBigAffine(&result)
}
// moduloReduce reduces k from more than 32 bytes to 32 bytes and under. This
// is done by doing a simple modulo curve.N. We can do this since G^N = 1 and
// thus any other valid point on the elliptic curve has the same order.
func moduloReduce(k []byte) []byte {
// Since the order of G is curve.N, we can use a much smaller number by
// doing modulo curve.N
if len(k) > curveParams.ByteSize {
tmpK := new(big.Int).SetBytes(k)
tmpK.Mod(tmpK, curveParams.N)
return tmpK.Bytes()
}
return k
}
// ScalarMult returns k*(Bx, By) where k is a big endian integer.
//
// This is part of the elliptic.Curve interface implementation.
func (curve *KoblitzCurve) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) {
// Convert the affine coordinates from big integers to Jacobian points,
// do the multiplication in Jacobian projective space, and convert the
// Jacobian point back to affine big.Ints.
var kModN ModNScalar
kModN.SetByteSlice(moduloReduce(k))
var point, result JacobianPoint
bigAffineToJacobian(Bx, By, &point)
ScalarMultNonConst(&kModN, &point, &result)
return jacobianToBigAffine(&result)
}
// ScalarBaseMult returns k*G where G is the base point of the group and k is a
// big endian integer.
//
// This is part of the elliptic.Curve interface implementation.
func (curve *KoblitzCurve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) {
// Perform the multiplication and convert the Jacobian point back to affine
// big.Ints.
var kModN ModNScalar
kModN.SetByteSlice(moduloReduce(k))
var result JacobianPoint
ScalarBaseMultNonConst(&kModN, &result)
return jacobianToBigAffine(&result)
}
// X returns the x coordinate of the public key.
func (p *PublicKey) X() *big.Int {
return new(big.Int).SetBytes(p.x.Bytes()[:])
}
// Y returns the y coordinate of the public key.
func (p *PublicKey) Y() *big.Int {
return new(big.Int).SetBytes(p.y.Bytes()[:])
}
// ToECDSA returns the public key as a *ecdsa.PublicKey.
func (p *PublicKey) ToECDSA() *ecdsa.PublicKey {
return &ecdsa.PublicKey{
Curve: S256(),
X: p.X(),
Y: p.Y(),
}
}
// ToECDSA returns the private key as a *ecdsa.PrivateKey.
func (p *PrivateKey) ToECDSA() *ecdsa.PrivateKey {
var privKeyBytes [PrivKeyBytesLen]byte
p.Key.PutBytes(&privKeyBytes)
var result JacobianPoint
ScalarBaseMultNonConst(&p.Key, &result)
x, y := jacobianToBigAffine(&result)
newPrivKey := &ecdsa.PrivateKey{
PublicKey: ecdsa.PublicKey{
Curve: S256(),
X: x,
Y: y,
},
D: new(big.Int).SetBytes(privKeyBytes[:]),
}
zeroArray32(&privKeyBytes)
return newPrivKey
}
// fromHex converts the passed hex string into a big integer pointer and will
// panic is there is an error. This is only provided for the hard-coded
// constants so errors in the source code can bet detected. It will only (and
// must only) be called for initialization purposes.
func fromHex(s string) *big.Int {
if s == "" {
return big.NewInt(0)
}
r, ok := new(big.Int).SetString(s, 16)
if !ok {
panic("invalid hex in source file: " + s)
}
return r
}
// secp256k1 is a global instance of the KoblitzCurve implementation which in
// turn embeds and implements elliptic.CurveParams.
var secp256k1 = &KoblitzCurve{
CurveParams: &elliptic.CurveParams{
P: curveParams.P,
N: curveParams.N,
B: fromHex("0000000000000000000000000000000000000000000000000000000000000007"),
Gx: curveParams.Gx,
Gy: curveParams.Gy,
BitSize: curveParams.BitSize,
Name: "secp256k1",
},
}
// S256 returns a Curve which implements secp256k1.
func S256() *KoblitzCurve {
return secp256k1
}

View File

@ -0,0 +1,67 @@
// Copyright (c) 2020 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package secp256k1
// ErrorKind identifies a kind of error. It has full support for errors.Is and
// errors.As, so the caller can directly check against an error kind when
// determining the reason for an error.
type ErrorKind string
// These constants are used to identify a specific RuleError.
const (
// ErrPubKeyInvalidLen indicates that the length of a serialized public
// key is not one of the allowed lengths.
ErrPubKeyInvalidLen = ErrorKind("ErrPubKeyInvalidLen")
// ErrPubKeyInvalidFormat indicates an attempt was made to parse a public
// key that does not specify one of the supported formats.
ErrPubKeyInvalidFormat = ErrorKind("ErrPubKeyInvalidFormat")
// ErrPubKeyXTooBig indicates that the x coordinate for a public key
// is greater than or equal to the prime of the field underlying the group.
ErrPubKeyXTooBig = ErrorKind("ErrPubKeyXTooBig")
// ErrPubKeyYTooBig indicates that the y coordinate for a public key is
// greater than or equal to the prime of the field underlying the group.
ErrPubKeyYTooBig = ErrorKind("ErrPubKeyYTooBig")
// ErrPubKeyNotOnCurve indicates that a public key is not a point on the
// secp256k1 curve.
ErrPubKeyNotOnCurve = ErrorKind("ErrPubKeyNotOnCurve")
// ErrPubKeyMismatchedOddness indicates that a hybrid public key specified
// an oddness of the y coordinate that does not match the actual oddness of
// the provided y coordinate.
ErrPubKeyMismatchedOddness = ErrorKind("ErrPubKeyMismatchedOddness")
)
// Error satisfies the error interface and prints human-readable errors.
func (e ErrorKind) Error() string {
return string(e)
}
// Error identifies an error related to public key cryptography using a
// sec256k1 curve. It has full support for errors.Is and errors.As, so the
// caller can ascertain the specific reason for the error by checking
// the underlying error.
type Error struct {
Err error
Description string
}
// Error satisfies the error interface and prints human-readable errors.
func (e Error) Error() string {
return e.Description
}
// Unwrap returns the underlying wrapped error.
func (e Error) Unwrap() error {
return e.Err
}
// makeError creates an Error given a set of arguments.
func makeError(kind ErrorKind, desc string) Error {
return Error{Err: kind, Description: desc}
}

1680
vendor/github.com/decred/dcrd/dcrec/secp256k1/v4/field.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,196 @@
// Copyright (c) 2014-2015 The btcsuite developers
// Copyright (c) 2015-2021 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
// This file is ignored during the regular build due to the following build tag.
// This build tag is set during go generate.
//go:build gensecp256k1
// +build gensecp256k1
package secp256k1
// References:
// [GECC]: Guide to Elliptic Curve Cryptography (Hankerson, Menezes, Vanstone)
import (
"encoding/binary"
"math/big"
)
// compressedBytePoints are dummy points used so the code which generates the
// real values can compile.
var compressedBytePoints = ""
// SerializedBytePoints returns a serialized byte slice which contains all of
// the possible points per 8-bit window. This is used to when generating
// compressedbytepoints.go.
func SerializedBytePoints() []byte {
// Calculate G^(2^i) for i in 0..255. These are used to avoid recomputing
// them for each digit of the 8-bit windows.
doublingPoints := make([]JacobianPoint, curveParams.BitSize)
var q JacobianPoint
bigAffineToJacobian(curveParams.Gx, curveParams.Gy, &q)
for i := 0; i < curveParams.BitSize; i++ {
// Q = 2*Q.
doublingPoints[i] = q
DoubleNonConst(&q, &q)
}
// Separate the bits into byte-sized windows.
curveByteSize := curveParams.BitSize / 8
serialized := make([]byte, curveByteSize*256*2*10*4)
offset := 0
for byteNum := 0; byteNum < curveByteSize; byteNum++ {
// Grab the 8 bits that make up this byte from doubling points.
startingBit := 8 * (curveByteSize - byteNum - 1)
windowPoints := doublingPoints[startingBit : startingBit+8]
// Compute all points in this window, convert them to affine, and
// serialize them.
for i := 0; i < 256; i++ {
var point JacobianPoint
for bit := 0; bit < 8; bit++ {
if i>>uint(bit)&1 == 1 {
AddNonConst(&point, &windowPoints[bit], &point)
}
}
point.ToAffine()
for i := 0; i < len(point.X.n); i++ {
binary.LittleEndian.PutUint32(serialized[offset:], point.X.n[i])
offset += 4
}
for i := 0; i < len(point.Y.n); i++ {
binary.LittleEndian.PutUint32(serialized[offset:], point.Y.n[i])
offset += 4
}
}
}
return serialized
}
// sqrt returns the square root of the provided big integer using Newton's
// method. It's only compiled and used during generation of pre-computed
// values, so speed is not a huge concern.
func sqrt(n *big.Int) *big.Int {
// Initial guess = 2^(log_2(n)/2)
guess := big.NewInt(2)
guess.Exp(guess, big.NewInt(int64(n.BitLen()/2)), nil)
// Now refine using Newton's method.
big2 := big.NewInt(2)
prevGuess := big.NewInt(0)
for {
prevGuess.Set(guess)
guess.Add(guess, new(big.Int).Div(n, guess))
guess.Div(guess, big2)
if guess.Cmp(prevGuess) == 0 {
break
}
}
return guess
}
// EndomorphismVectors runs the first 3 steps of algorithm 3.74 from [GECC] to
// generate the linearly independent vectors needed to generate a balanced
// length-two representation of a multiplier such that k = k1 + k2λ (mod N) and
// returns them. Since the values will always be the same given the fact that N
// and λ are fixed, the final results can be accelerated by storing the
// precomputed values.
func EndomorphismVectors() (a1, b1, a2, b2 *big.Int) {
bigMinus1 := big.NewInt(-1)
// This section uses an extended Euclidean algorithm to generate a
// sequence of equations:
// s[i] * N + t[i] * λ = r[i]
nSqrt := sqrt(curveParams.N)
u, v := new(big.Int).Set(curveParams.N), new(big.Int).Set(endomorphismLambda)
x1, y1 := big.NewInt(1), big.NewInt(0)
x2, y2 := big.NewInt(0), big.NewInt(1)
q, r := new(big.Int), new(big.Int)
qu, qx1, qy1 := new(big.Int), new(big.Int), new(big.Int)
s, t := new(big.Int), new(big.Int)
ri, ti := new(big.Int), new(big.Int)
a1, b1, a2, b2 = new(big.Int), new(big.Int), new(big.Int), new(big.Int)
found, oneMore := false, false
for u.Sign() != 0 {
// q = v/u
q.Div(v, u)
// r = v - q*u
qu.Mul(q, u)
r.Sub(v, qu)
// s = x2 - q*x1
qx1.Mul(q, x1)
s.Sub(x2, qx1)
// t = y2 - q*y1
qy1.Mul(q, y1)
t.Sub(y2, qy1)
// v = u, u = r, x2 = x1, x1 = s, y2 = y1, y1 = t
v.Set(u)
u.Set(r)
x2.Set(x1)
x1.Set(s)
y2.Set(y1)
y1.Set(t)
// As soon as the remainder is less than the sqrt of n, the
// values of a1 and b1 are known.
if !found && r.Cmp(nSqrt) < 0 {
// When this condition executes ri and ti represent the
// r[i] and t[i] values such that i is the greatest
// index for which r >= sqrt(n). Meanwhile, the current
// r and t values are r[i+1] and t[i+1], respectively.
// a1 = r[i+1], b1 = -t[i+1]
a1.Set(r)
b1.Mul(t, bigMinus1)
found = true
oneMore = true
// Skip to the next iteration so ri and ti are not
// modified.
continue
} else if oneMore {
// When this condition executes ri and ti still
// represent the r[i] and t[i] values while the current
// r and t are r[i+2] and t[i+2], respectively.
// sum1 = r[i]^2 + t[i]^2
rSquared := new(big.Int).Mul(ri, ri)
tSquared := new(big.Int).Mul(ti, ti)
sum1 := new(big.Int).Add(rSquared, tSquared)
// sum2 = r[i+2]^2 + t[i+2]^2
r2Squared := new(big.Int).Mul(r, r)
t2Squared := new(big.Int).Mul(t, t)
sum2 := new(big.Int).Add(r2Squared, t2Squared)
// if (r[i]^2 + t[i]^2) <= (r[i+2]^2 + t[i+2]^2)
if sum1.Cmp(sum2) <= 0 {
// a2 = r[i], b2 = -t[i]
a2.Set(ri)
b2.Mul(ti, bigMinus1)
} else {
// a2 = r[i+2], b2 = -t[i+2]
a2.Set(r)
b2.Mul(t, bigMinus1)
}
// All done.
break
}
ri.Set(r)
ti.Set(t)
}
return a1, b1, a2, b2
}

View File

@ -0,0 +1,91 @@
// Copyright 2015 The btcsuite developers
// Copyright (c) 2015-2021 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package secp256k1
import (
"compress/zlib"
"encoding/base64"
"encoding/binary"
"io"
"strings"
"sync"
)
//go:generate go run -tags gensecp256k1 genprecomps.go
// bytePointTable describes a table used to house pre-computed values for
// accelerating scalar base multiplication.
type bytePointTable [32][256][2]FieldVal
// s256BytePoints houses pre-computed values used to accelerate scalar base
// multiplication such that they are only loaded on first use.
var s256BytePoints = func() func() *bytePointTable {
// mustLoadBytePoints decompresses and deserializes the pre-computed byte
// points used to accelerate scalar base multiplication for the secp256k1
// curve.
//
// This approach is used since it allows the compile to use significantly
// less ram and be performed much faster than it is with hard-coding the
// final in-memory data structure. At the same time, it is quite fast to
// generate the in-memory data structure on first use with this approach
// versus computing the table.
//
// It will panic on any errors because the data is hard coded and thus any
// errors means something is wrong in the source code.
var data *bytePointTable
mustLoadBytePoints := func() {
// There will be no byte points to load when generating them.
bp := compressedBytePoints
if len(bp) == 0 {
return
}
// Decompress the pre-computed table used to accelerate scalar base
// multiplication.
decoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(bp))
r, err := zlib.NewReader(decoder)
if err != nil {
panic(err)
}
serialized, err := io.ReadAll(r)
if err != nil {
panic(err)
}
// Deserialize the precomputed byte points and set the memory table to
// them.
offset := 0
var bytePoints bytePointTable
for byteNum := 0; byteNum < len(bytePoints); byteNum++ {
// All points in this window.
for i := 0; i < len(bytePoints[byteNum]); i++ {
px := &bytePoints[byteNum][i][0]
py := &bytePoints[byteNum][i][1]
for i := 0; i < len(px.n); i++ {
px.n[i] = binary.LittleEndian.Uint32(serialized[offset:])
offset += 4
}
for i := 0; i < len(py.n); i++ {
py.n[i] = binary.LittleEndian.Uint32(serialized[offset:])
offset += 4
}
}
}
data = &bytePoints
}
// Return a closure that initializes the data on first access. This is done
// because the table takes a non-trivial amount of memory and initializing
// it unconditionally would cause anything that imports the package, either
// directly, or indirectly via transitive deps, to use that memory even if
// the caller never accesses any parts of the package that actually needs
// access to it.
var loadBytePointsOnce sync.Once
return func() *bytePointTable {
loadBytePointsOnce.Do(mustLoadBytePoints)
return data
}
}()

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,263 @@
// Copyright (c) 2013-2014 The btcsuite developers
// Copyright (c) 2015-2020 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package secp256k1
import (
"bytes"
"crypto/sha256"
"hash"
)
// References:
// [GECC]: Guide to Elliptic Curve Cryptography (Hankerson, Menezes, Vanstone)
//
// [ISO/IEC 8825-1]: Information technology — ASN.1 encoding rules:
// Specification of Basic Encoding Rules (BER), Canonical Encoding Rules
// (CER) and Distinguished Encoding Rules (DER)
//
// [SEC1]: Elliptic Curve Cryptography (May 31, 2009, Version 2.0)
// https://www.secg.org/sec1-v2.pdf
var (
// singleZero is used during RFC6979 nonce generation. It is provided
// here to avoid the need to create it multiple times.
singleZero = []byte{0x00}
// zeroInitializer is used during RFC6979 nonce generation. It is provided
// here to avoid the need to create it multiple times.
zeroInitializer = bytes.Repeat([]byte{0x00}, sha256.BlockSize)
// singleOne is used during RFC6979 nonce generation. It is provided
// here to avoid the need to create it multiple times.
singleOne = []byte{0x01}
// oneInitializer is used during RFC6979 nonce generation. It is provided
// here to avoid the need to create it multiple times.
oneInitializer = bytes.Repeat([]byte{0x01}, sha256.Size)
)
// hmacsha256 implements a resettable version of HMAC-SHA256.
type hmacsha256 struct {
inner, outer hash.Hash
ipad, opad [sha256.BlockSize]byte
}
// Write adds data to the running hash.
func (h *hmacsha256) Write(p []byte) {
h.inner.Write(p)
}
// initKey initializes the HMAC-SHA256 instance to the provided key.
func (h *hmacsha256) initKey(key []byte) {
// Hash the key if it is too large.
if len(key) > sha256.BlockSize {
h.outer.Write(key)
key = h.outer.Sum(nil)
}
copy(h.ipad[:], key)
copy(h.opad[:], key)
for i := range h.ipad {
h.ipad[i] ^= 0x36
}
for i := range h.opad {
h.opad[i] ^= 0x5c
}
h.inner.Write(h.ipad[:])
}
// ResetKey resets the HMAC-SHA256 to its initial state and then initializes it
// with the provided key. It is equivalent to creating a new instance with the
// provided key without allocating more memory.
func (h *hmacsha256) ResetKey(key []byte) {
h.inner.Reset()
h.outer.Reset()
copy(h.ipad[:], zeroInitializer)
copy(h.opad[:], zeroInitializer)
h.initKey(key)
}
// Resets the HMAC-SHA256 to its initial state using the current key.
func (h *hmacsha256) Reset() {
h.inner.Reset()
h.inner.Write(h.ipad[:])
}
// Sum returns the hash of the written data.
func (h *hmacsha256) Sum() []byte {
h.outer.Reset()
h.outer.Write(h.opad[:])
h.outer.Write(h.inner.Sum(nil))
return h.outer.Sum(nil)
}
// newHMACSHA256 returns a new HMAC-SHA256 hasher using the provided key.
func newHMACSHA256(key []byte) *hmacsha256 {
h := new(hmacsha256)
h.inner = sha256.New()
h.outer = sha256.New()
h.initKey(key)
return h
}
// NonceRFC6979 generates a nonce deterministically according to RFC 6979 using
// HMAC-SHA256 for the hashing function. It takes a 32-byte hash as an input
// and returns a 32-byte nonce to be used for deterministic signing. The extra
// and version arguments are optional, but allow additional data to be added to
// the input of the HMAC. When provided, the extra data must be 32-bytes and
// version must be 16 bytes or they will be ignored.
//
// Finally, the extraIterations parameter provides a method to produce a stream
// of deterministic nonces to ensure the signing code is able to produce a nonce
// that results in a valid signature in the extremely unlikely event the
// original nonce produced results in an invalid signature (e.g. R == 0).
// Signing code should start with 0 and increment it if necessary.
func NonceRFC6979(privKey []byte, hash []byte, extra []byte, version []byte, extraIterations uint32) *ModNScalar {
// Input to HMAC is the 32-byte private key and the 32-byte hash. In
// addition, it may include the optional 32-byte extra data and 16-byte
// version. Create a fixed-size array to avoid extra allocs and slice it
// properly.
const (
privKeyLen = 32
hashLen = 32
extraLen = 32
versionLen = 16
)
var keyBuf [privKeyLen + hashLen + extraLen + versionLen]byte
// Truncate rightmost bytes of private key and hash if they are too long and
// leave left padding of zeros when they're too short.
if len(privKey) > privKeyLen {
privKey = privKey[:privKeyLen]
}
if len(hash) > hashLen {
hash = hash[:hashLen]
}
offset := privKeyLen - len(privKey) // Zero left padding if needed.
offset += copy(keyBuf[offset:], privKey)
offset += hashLen - len(hash) // Zero left padding if needed.
offset += copy(keyBuf[offset:], hash)
if len(extra) == extraLen {
offset += copy(keyBuf[offset:], extra)
if len(version) == versionLen {
offset += copy(keyBuf[offset:], version)
}
} else if len(version) == versionLen {
// When the version was specified, but not the extra data, leave the
// extra data portion all zero.
offset += privKeyLen
offset += copy(keyBuf[offset:], version)
}
key := keyBuf[:offset]
// Step B.
//
// V = 0x01 0x01 0x01 ... 0x01 such that the length of V, in bits, is
// equal to 8*ceil(hashLen/8).
//
// Note that since the hash length is a multiple of 8 for the chosen hash
// function in this optimized implementation, the result is just the hash
// length, so avoid the extra calculations. Also, since it isn't modified,
// start with a global value.
v := oneInitializer
// Step C (Go zeroes all allocated memory).
//
// K = 0x00 0x00 0x00 ... 0x00 such that the length of K, in bits, is
// equal to 8*ceil(hashLen/8).
//
// As above, since the hash length is a multiple of 8 for the chosen hash
// function in this optimized implementation, the result is just the hash
// length, so avoid the extra calculations.
k := zeroInitializer[:hashLen]
// Step D.
//
// K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1))
//
// Note that key is the "int2octets(x) || bits2octets(h1)" portion along
// with potential additional data as described by section 3.6 of the RFC.
hasher := newHMACSHA256(k)
hasher.Write(oneInitializer)
hasher.Write(singleZero[:])
hasher.Write(key)
k = hasher.Sum()
// Step E.
//
// V = HMAC_K(V)
hasher.ResetKey(k)
hasher.Write(v)
v = hasher.Sum()
// Step F.
//
// K = HMAC_K(V || 0x01 || int2octets(x) || bits2octets(h1))
//
// Note that key is the "int2octets(x) || bits2octets(h1)" portion along
// with potential additional data as described by section 3.6 of the RFC.
hasher.Reset()
hasher.Write(v)
hasher.Write(singleOne[:])
hasher.Write(key[:])
k = hasher.Sum()
// Step G.
//
// V = HMAC_K(V)
hasher.ResetKey(k)
hasher.Write(v)
v = hasher.Sum()
// Step H.
//
// Repeat until the value is nonzero and less than the curve order.
var generated uint32
for {
// Step H1 and H2.
//
// Set T to the empty sequence. The length of T (in bits) is denoted
// tlen; thus, at that point, tlen = 0.
//
// While tlen < qlen, do the following:
// V = HMAC_K(V)
// T = T || V
//
// Note that because the hash function output is the same length as the
// private key in this optimized implementation, there is no need to
// loop or create an intermediate T.
hasher.Reset()
hasher.Write(v)
v = hasher.Sum()
// Step H3.
//
// k = bits2int(T)
// If k is within the range [1,q-1], return it.
//
// Otherwise, compute:
// K = HMAC_K(V || 0x00)
// V = HMAC_K(V)
var secret ModNScalar
overflow := secret.SetByteSlice(v)
if !overflow && !secret.IsZero() {
generated++
if generated > extraIterations {
return &secret
}
}
// K = HMAC_K(V || 0x00)
hasher.Reset()
hasher.Write(v)
hasher.Write(singleZero[:])
k = hasher.Sum()
// V = HMAC_K(V)
hasher.ResetKey(k)
hasher.Write(v)
v = hasher.Sum()
}
}

View File

@ -0,0 +1,77 @@
// Copyright (c) 2013-2014 The btcsuite developers
// Copyright (c) 2015-2020 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package secp256k1
import (
"crypto/ecdsa"
"crypto/rand"
)
// PrivateKey provides facilities for working with secp256k1 private keys within
// this package and includes functionality such as serializing and parsing them
// as well as computing their associated public key.
type PrivateKey struct {
Key ModNScalar
}
// NewPrivateKey instantiates a new private key from a scalar encoded as a
// big integer.
func NewPrivateKey(key *ModNScalar) *PrivateKey {
return &PrivateKey{Key: *key}
}
// PrivKeyFromBytes returns a private based on the provided byte slice which is
// interpreted as an unsigned 256-bit big-endian integer in the range [0, N-1],
// where N is the order of the curve.
//
// Note that this means passing a slice with more than 32 bytes is truncated and
// that truncated value is reduced modulo N. It is up to the caller to either
// provide a value in the appropriate range or choose to accept the described
// behavior.
//
// Typically callers should simply make use of GeneratePrivateKey when creating
// private keys which properly handles generation of appropriate values.
func PrivKeyFromBytes(privKeyBytes []byte) *PrivateKey {
var privKey PrivateKey
privKey.Key.SetByteSlice(privKeyBytes)
return &privKey
}
// GeneratePrivateKey returns a private key that is suitable for use with
// secp256k1.
func GeneratePrivateKey() (*PrivateKey, error) {
key, err := ecdsa.GenerateKey(S256(), rand.Reader)
if err != nil {
return nil, err
}
return PrivKeyFromBytes(key.D.Bytes()), nil
}
// PubKey computes and returns the public key corresponding to this private key.
func (p *PrivateKey) PubKey() *PublicKey {
var result JacobianPoint
ScalarBaseMultNonConst(&p.Key, &result)
result.ToAffine()
return NewPublicKey(&result.X, &result.Y)
}
// Zero manually clears the memory associated with the private key. This can be
// used to explicitly clear key material from memory for enhanced security
// against memory scraping.
func (p *PrivateKey) Zero() {
p.Key.Zero()
}
// PrivKeyBytesLen defines the length in bytes of a serialized private key.
const PrivKeyBytesLen = 32
// Serialize returns the private key as a 256-bit big-endian binary-encoded
// number, padded to a length of 32 bytes.
func (p PrivateKey) Serialize() []byte {
var privKeyBytes [PrivKeyBytesLen]byte
p.Key.PutBytes(&privKeyBytes)
return privKeyBytes[:]
}

View File

@ -0,0 +1,232 @@
// Copyright (c) 2013-2014 The btcsuite developers
// Copyright (c) 2015-2021 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package secp256k1
// References:
// [SEC1] Elliptic Curve Cryptography
// https://www.secg.org/sec1-v2.pdf
//
// [SEC2] Recommended Elliptic Curve Domain Parameters
// https://www.secg.org/sec2-v2.pdf
//
// [ANSI X9.62-1998] Public Key Cryptography For The Financial Services
// Industry: The Elliptic Curve Digital Signature Algorithm (ECDSA)
import (
"fmt"
)
const (
// PubKeyBytesLenCompressed is the number of bytes of a serialized
// compressed public key.
PubKeyBytesLenCompressed = 33
// PubKeyBytesLenUncompressed is the number of bytes of a serialized
// uncompressed public key.
PubKeyBytesLenUncompressed = 65
// PubKeyFormatCompressedEven is the identifier prefix byte for a public key
// whose Y coordinate is even when serialized in the compressed format per
// section 2.3.4 of [SEC1](https://secg.org/sec1-v2.pdf#subsubsection.2.3.4).
PubKeyFormatCompressedEven byte = 0x02
// PubKeyFormatCompressedOdd is the identifier prefix byte for a public key
// whose Y coordinate is odd when serialized in the compressed format per
// section 2.3.4 of [SEC1](https://secg.org/sec1-v2.pdf#subsubsection.2.3.4).
PubKeyFormatCompressedOdd byte = 0x03
// PubKeyFormatUncompressed is the identifier prefix byte for a public key
// when serialized according in the uncompressed format per section 2.3.3 of
// [SEC1](https://secg.org/sec1-v2.pdf#subsubsection.2.3.3).
PubKeyFormatUncompressed byte = 0x04
// PubKeyFormatHybridEven is the identifier prefix byte for a public key
// whose Y coordinate is even when serialized according to the hybrid format
// per section 4.3.6 of [ANSI X9.62-1998].
//
// NOTE: This format makes little sense in practice an therefore this
// package will not produce public keys serialized in this format. However,
// it will parse them since they exist in the wild.
PubKeyFormatHybridEven byte = 0x06
// PubKeyFormatHybridOdd is the identifier prefix byte for a public key
// whose Y coordingate is odd when serialized according to the hybrid format
// per section 4.3.6 of [ANSI X9.62-1998].
//
// NOTE: This format makes little sense in practice an therefore this
// package will not produce public keys serialized in this format. However,
// it will parse them since they exist in the wild.
PubKeyFormatHybridOdd byte = 0x07
)
// PublicKey provides facilities for efficiently working with secp256k1 public
// keys within this package and includes functions to serialize in both
// uncompressed and compressed SEC (Standards for Efficient Cryptography)
// formats.
type PublicKey struct {
x FieldVal
y FieldVal
}
// NewPublicKey instantiates a new public key with the given x and y
// coordinates.
//
// It should be noted that, unlike ParsePubKey, since this accepts arbitrary x
// and y coordinates, it allows creation of public keys that are not valid
// points on the secp256k1 curve. The IsOnCurve method of the returned instance
// can be used to determine validity.
func NewPublicKey(x, y *FieldVal) *PublicKey {
var pubKey PublicKey
pubKey.x.Set(x)
pubKey.y.Set(y)
return &pubKey
}
// ParsePubKey parses a secp256k1 public key encoded according to the format
// specified by ANSI X9.62-1998, which means it is also compatible with the
// SEC (Standards for Efficient Cryptography) specification which is a subset of
// the former. In other words, it supports the uncompressed, compressed, and
// hybrid formats as follows:
//
// Compressed:
// <format byte = 0x02/0x03><32-byte X coordinate>
// Uncompressed:
// <format byte = 0x04><32-byte X coordinate><32-byte Y coordinate>
// Hybrid:
// <format byte = 0x05/0x06><32-byte X coordinate><32-byte Y coordinate>
//
// NOTE: The hybrid format makes little sense in practice an therefore this
// package will not produce public keys serialized in this format. However,
// this function will properly parse them since they exist in the wild.
func ParsePubKey(serialized []byte) (key *PublicKey, err error) {
var x, y FieldVal
switch len(serialized) {
case PubKeyBytesLenUncompressed:
// Reject unsupported public key formats for the given length.
format := serialized[0]
switch format {
case PubKeyFormatUncompressed:
case PubKeyFormatHybridEven, PubKeyFormatHybridOdd:
default:
str := fmt.Sprintf("invalid public key: unsupported format: %x",
format)
return nil, makeError(ErrPubKeyInvalidFormat, str)
}
// Parse the x and y coordinates while ensuring that they are in the
// allowed range.
if overflow := x.SetByteSlice(serialized[1:33]); overflow {
str := "invalid public key: x >= field prime"
return nil, makeError(ErrPubKeyXTooBig, str)
}
if overflow := y.SetByteSlice(serialized[33:]); overflow {
str := "invalid public key: y >= field prime"
return nil, makeError(ErrPubKeyYTooBig, str)
}
// Ensure the oddness of the y coordinate matches the specified format
// for hybrid public keys.
if format == PubKeyFormatHybridEven || format == PubKeyFormatHybridOdd {
wantOddY := format == PubKeyFormatHybridOdd
if y.IsOdd() != wantOddY {
str := fmt.Sprintf("invalid public key: y oddness does not "+
"match specified value of %v", wantOddY)
return nil, makeError(ErrPubKeyMismatchedOddness, str)
}
}
// Reject public keys that are not on the secp256k1 curve.
if !isOnCurve(&x, &y) {
str := fmt.Sprintf("invalid public key: [%v,%v] not on secp256k1 "+
"curve", x, y)
return nil, makeError(ErrPubKeyNotOnCurve, str)
}
case PubKeyBytesLenCompressed:
// Reject unsupported public key formats for the given length.
format := serialized[0]
switch format {
case PubKeyFormatCompressedEven, PubKeyFormatCompressedOdd:
default:
str := fmt.Sprintf("invalid public key: unsupported format: %x",
format)
return nil, makeError(ErrPubKeyInvalidFormat, str)
}
// Parse the x coordinate while ensuring that it is in the allowed
// range.
if overflow := x.SetByteSlice(serialized[1:33]); overflow {
str := "invalid public key: x >= field prime"
return nil, makeError(ErrPubKeyXTooBig, str)
}
// Attempt to calculate the y coordinate for the given x coordinate such
// that the result pair is a point on the secp256k1 curve and the
// solution with desired oddness is chosen.
wantOddY := format == PubKeyFormatCompressedOdd
if !DecompressY(&x, wantOddY, &y) {
str := fmt.Sprintf("invalid public key: x coordinate %v is not on "+
"the secp256k1 curve", x)
return nil, makeError(ErrPubKeyNotOnCurve, str)
}
y.Normalize()
default:
str := fmt.Sprintf("malformed public key: invalid length: %d",
len(serialized))
return nil, makeError(ErrPubKeyInvalidLen, str)
}
return NewPublicKey(&x, &y), nil
}
// SerializeUncompressed serializes a public key in the 65-byte uncompressed
// format.
func (p PublicKey) SerializeUncompressed() []byte {
// 0x04 || 32-byte x coordinate || 32-byte y coordinate
var b [PubKeyBytesLenUncompressed]byte
b[0] = PubKeyFormatUncompressed
p.x.PutBytesUnchecked(b[1:33])
p.y.PutBytesUnchecked(b[33:65])
return b[:]
}
// SerializeCompressed serializes a public key in the 33-byte compressed format.
func (p PublicKey) SerializeCompressed() []byte {
// Choose the format byte depending on the oddness of the Y coordinate.
format := PubKeyFormatCompressedEven
if p.y.IsOdd() {
format = PubKeyFormatCompressedOdd
}
// 0x02 or 0x03 || 32-byte x coordinate
var b [PubKeyBytesLenCompressed]byte
b[0] = format
p.x.PutBytesUnchecked(b[1:33])
return b[:]
}
// IsEqual compares this PublicKey instance to the one passed, returning true if
// both PublicKeys are equivalent. A PublicKey is equivalent to another, if they
// both have the same X and Y coordinate.
func (p *PublicKey) IsEqual(otherPubKey *PublicKey) bool {
return p.x.Equals(&otherPubKey.x) && p.y.Equals(&otherPubKey.y)
}
// AsJacobian converts the public key into a Jacobian point with Z=1 and stores
// the result in the provided result param. This allows the public key to be
// treated a Jacobian point in the secp256k1 group in calculations.
func (p *PublicKey) AsJacobian(result *JacobianPoint) {
result.X.Set(&p.x)
result.Y.Set(&p.y)
result.Z.SetInt(1)
}
// IsOnCurve returns whether or not the public key represents a point on the
// secp256k1 curve.
func (p *PublicKey) IsOnCurve() bool {
return isOnCurve(&p.x, &p.y)
}

View File

@ -15,6 +15,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Deprecated
## [0.14.2]
### Fixed
- Fix again unsupported devices for filesystem. [#164](https://github.com/elastic/gosigar/pull/164)
## [0.14.1]
### Fixed

View File

@ -130,7 +130,6 @@ func (self *FileSystemList) Get() error {
if err != nil {
return errors.Wrap(err, "GetAccessPaths failed")
}
for _, drive := range drives {
dt, err := windows.GetDriveType(drive)
if err != nil {
@ -140,14 +139,12 @@ func (self *FileSystemList) Get() error {
if err != nil {
return errors.Wrapf(err, "GetFilesystemType failed")
}
if fsType != "" {
self.List = append(self.List, FileSystem{
DirName: drive,
DevName: drive,
TypeName: dt.String(),
SysTypeName: fsType,
})
}
self.List = append(self.List, FileSystem{
DirName: drive,
DevName: drive,
TypeName: dt.String(),
SysTypeName: fsType,
})
}
return nil
}

View File

@ -346,21 +346,17 @@ func GetDriveType(rootPathName string) (DriveType, error) {
// https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getvolumeinformationw
func GetFilesystemType(rootPathName string) (string, error) {
rootPathNamePtr, err := syscall.UTF16PtrFromString(rootPathName)
var systemType = "unavailable"
if err != nil {
return "", errors.Wrapf(err, "UTF16PtrFromString failed for rootPathName=%v", rootPathName)
}
buffer := make([]uint16, MAX_PATH+1)
// _GetVolumeInformation will fail for external drives like CD-ROM or other type with error codes as ERROR_NOT_READY. ERROR_INVALID_FUNCTION, ERROR_INVALID_PARAMETER, etc., these types of errors will be ignored
success, err := _GetVolumeInformation(rootPathNamePtr, nil, 0, nil, nil, nil, &buffer[0], MAX_PATH)
// check if CD-ROM or other type that is not supported in GetVolumeInformation function
if err == ERROR_NOT_READY || err == ERROR_INVALID_FUNCTION {
return "", nil
if success {
systemType = strings.ToLower(syscall.UTF16ToString(buffer))
}
if !success {
return "", errors.Wrap(err, "GetVolumeInformationW failed")
}
return strings.ToLower(syscall.UTF16ToString(buffer)), nil
return systemType, nil
}
// EnumProcesses retrieves the process identifier for each process object in the

View File

@ -86,6 +86,11 @@ func (s *CipherState) Nonce() uint64 {
return s.n
}
// SetNonce sets the current value of n.
func (s *CipherState) SetNonce(n uint64) {
s.n = n
}
func (s *CipherState) Rekey() {
var zeros [32]byte
var out []byte
@ -448,6 +453,110 @@ func (s *HandshakeState) WriteMessage(out, payload []byte) ([]byte, *CipherState
return out, nil, nil, nil
}
// WriteMessageAndGetPK appends a handshake message to out. outPK can possibly contain the
// party public keys. The message will include the optional payload if provided.
// If the handshake is completed by the call, two CipherStates will be returned,
// one is used for encryption of messages to the remote peer, the other is used
// for decryption of messages from the remote peer. It is an error to call this
// method out of sync with the handshake pattern.
func (s *HandshakeState) WriteMessageAndGetPK(out []byte, outNoisePK *[][]byte, payload []byte) ([]byte, *CipherState, *CipherState, error) {
if !s.shouldWrite {
return nil, nil, nil, errors.New("noise: unexpected call to WriteMessage should be ReadMessage")
}
if s.msgIdx > len(s.messagePatterns)-1 {
return nil, nil, nil, errors.New("noise: no handshake messages left")
}
if len(payload) > MaxMsgLen {
return nil, nil, nil, errors.New("noise: message is too long")
}
var err error
for _, msg := range s.messagePatterns[s.msgIdx] {
switch msg {
case MessagePatternE:
e, err := s.ss.cs.GenerateKeypair(s.rng)
if err != nil {
return nil, nil, nil, err
}
s.e = e
out = append(out, s.e.Public...)
if outNoisePK != nil {
*outNoisePK = append(*outNoisePK, s.e.Public)
}
s.ss.MixHash(s.e.Public)
if len(s.psk) > 0 {
s.ss.MixKey(s.e.Public)
}
case MessagePatternS:
if len(s.s.Public) == 0 {
return nil, nil, nil, errors.New("noise: invalid state, s.Public is nil")
}
out, err = s.ss.EncryptAndHash(out, s.s.Public)
if err != nil {
return nil, nil, nil, err
}
if outNoisePK != nil {
*outNoisePK = append(*outNoisePK, out)
}
case MessagePatternDHEE:
dh, err := s.ss.cs.DH(s.e.Private, s.re)
if err != nil {
return nil, nil, nil, err
}
s.ss.MixKey(dh)
case MessagePatternDHES:
if s.initiator {
dh, err := s.ss.cs.DH(s.e.Private, s.rs)
if err != nil {
return nil, nil, nil, err
}
s.ss.MixKey(dh)
} else {
dh, err := s.ss.cs.DH(s.s.Private, s.re)
if err != nil {
return nil, nil, nil, err
}
s.ss.MixKey(dh)
}
case MessagePatternDHSE:
if s.initiator {
dh, err := s.ss.cs.DH(s.s.Private, s.re)
if err != nil {
return nil, nil, nil, err
}
s.ss.MixKey(dh)
} else {
dh, err := s.ss.cs.DH(s.e.Private, s.rs)
if err != nil {
return nil, nil, nil, err
}
s.ss.MixKey(dh)
}
case MessagePatternDHSS:
dh, err := s.ss.cs.DH(s.s.Private, s.rs)
if err != nil {
return nil, nil, nil, err
}
s.ss.MixKey(dh)
case MessagePatternPSK:
s.ss.MixKeyAndHash(s.psk)
}
}
s.shouldWrite = false
s.msgIdx++
out, err = s.ss.EncryptAndHash(out, payload)
if err != nil {
return nil, nil, nil, err
}
if s.msgIdx >= len(s.messagePatterns) {
cs1, cs2 := s.ss.Split()
return out, cs1, cs2, nil
}
return out, nil, nil, nil
}
// ErrShortMessage is returned by ReadMessage if a message is not as long as it should be.
var ErrShortMessage = errors.New("noise: message is too short")

View File

@ -7,9 +7,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
## [1.5.4] - 2022-04-25
* Windows: add missing defer to `Watcher.WatchList` [#447](https://github.com/fsnotify/fsnotify/pull/447)
* go.mod: use latest x/sys [#444](https://github.com/fsnotify/fsnotify/pull/444)
* Fix compilation for OpenBSD [#443](https://github.com/fsnotify/fsnotify/pull/443)
## [1.5.3] - 2022-04-22
* This version is retracted. An incorrect branch is published accidentally [#445](https://github.com/fsnotify/fsnotify/issues/445)
## [1.5.2] - 2022-04-21
* Add a feature to return the directories and files that are being monitored [#374](https://github.com/fsnotify/fsnotify/pull/374)
* Fix potential crash on windows if `raw.FileNameLength` exceeds `syscall.MAX_PATH` [#361](https://github.com/fsnotify/fsnotify/pull/361)
* Allow build on unsupported GOOS [#424](https://github.com/fsnotify/fsnotify/pull/424)
* Don't set `poller.fd` twice in `newFdPoller` [#406](https://github.com/fsnotify/fsnotify/pull/406)
* fix go vet warnings: call to `(*T).Fatalf` from a non-test goroutine [#416](https://github.com/fsnotify/fsnotify/pull/416)
## [1.5.1] - 2021-08-24
* Revert Add AddRaw to not follow symlinks
* Revert Add AddRaw to not follow symlinks [#394](https://github.com/fsnotify/fsnotify/pull/394)
## [1.5.0] - 2021-08-20

View File

@ -48,18 +48,6 @@ fsnotify uses build tags to compile different code on Linux, BSD, macOS, and Win
Before doing a pull request, please do your best to test your changes on multiple platforms, and list which platforms you were able/unable to test on.
To aid in cross-platform testing there is a Vagrantfile for Linux and BSD.
* Install [Vagrant](http://www.vagrantup.com/) and [VirtualBox](https://www.virtualbox.org/)
* Setup [Vagrant Gopher](https://github.com/nathany/vagrant-gopher) in your `src` folder.
* Run `vagrant up` from the project folder. You can also setup just one box with `vagrant up linux` or `vagrant up bsd` (note: the BSD box doesn't support Windows hosts at this time, and NFS may prompt for your host OS password)
* Once setup, you can run the test suite on a given OS with a single command `vagrant ssh linux -c 'cd fsnotify/fsnotify; go test'`.
* When you're done, you will want to halt or destroy the Vagrant boxes.
Notice: fsnotify file system events won't trigger in shared folders. The tests get around this limitation by using the /tmp directory.
Right now there is no equivalent solution for Windows and macOS, but there are Windows VMs [freely available from Microsoft](http://www.modern.ie/en-us/virtualization-tools#downloads).
### Maintainers
Help maintaining fsnotify is welcome. To be a maintainer:
@ -67,11 +55,6 @@ Help maintaining fsnotify is welcome. To be a maintainer:
* Submit a pull request and sign the CLA as above.
* You must be able to run the test suite on Mac, Windows, Linux and BSD.
To keep master clean, the fsnotify project uses the "apply mail" workflow outlined in Nathaniel Talbott's post ["Merge pull request" Considered Harmful][am]. This requires installing [hub][].
All code changes should be internal pull requests.
Releases are tagged using [Semantic Versioning](http://semver.org/).
[hub]: https://github.com/github/hub
[am]: http://blog.spreedly.com/2014/06/24/merge-pull-request-considered-harmful/#.VGa5yZPF_Zs

View File

@ -1,12 +1,8 @@
# File system notifications for Go
[![GoDoc](https://godoc.org/github.com/fsnotify/fsnotify?status.svg)](https://godoc.org/github.com/fsnotify/fsnotify) [![Go Report Card](https://goreportcard.com/badge/github.com/fsnotify/fsnotify)](https://goreportcard.com/report/github.com/fsnotify/fsnotify)
[![Go Reference](https://pkg.go.dev/badge/github.com/fsnotify/fsnotify.svg)](https://pkg.go.dev/github.com/fsnotify/fsnotify) [![Go Report Card](https://goreportcard.com/badge/github.com/fsnotify/fsnotify)](https://goreportcard.com/report/github.com/fsnotify/fsnotify) [![Maintainers Wanted](https://img.shields.io/badge/maintainers-wanted-red.svg)](https://github.com/fsnotify/fsnotify/issues/413)
fsnotify utilizes [golang.org/x/sys](https://godoc.org/golang.org/x/sys) rather than `syscall` from the standard library. Ensure you have the latest version installed by running:
```console
go get -u golang.org/x/sys/...
```
fsnotify utilizes [`golang.org/x/sys`](https://pkg.go.dev/golang.org/x/sys) rather than [`syscall`](https://pkg.go.dev/syscall) from the standard library.
Cross platform: Windows, Linux, BSD and macOS.
@ -16,22 +12,20 @@ Cross platform: Windows, Linux, BSD and macOS.
| kqueue | BSD, macOS, iOS\* | Supported |
| ReadDirectoryChangesW | Windows | Supported |
| FSEvents | macOS | [Planned](https://github.com/fsnotify/fsnotify/issues/11) |
| FEN | Solaris 11 | [In Progress](https://github.com/fsnotify/fsnotify/issues/12) |
| fanotify | Linux 2.6.37+ | [Planned](https://github.com/fsnotify/fsnotify/issues/114) |
| FEN | Solaris 11 | [In Progress](https://github.com/fsnotify/fsnotify/pull/371) |
| fanotify | Linux 2.6.37+ | [Maybe](https://github.com/fsnotify/fsnotify/issues/114) |
| USN Journals | Windows | [Maybe](https://github.com/fsnotify/fsnotify/issues/53) |
| Polling | *All* | [Maybe](https://github.com/fsnotify/fsnotify/issues/9) |
\* Android and iOS are untested.
Please see [the documentation](https://godoc.org/github.com/fsnotify/fsnotify) and consult the [FAQ](#faq) for usage information.
Please see [the documentation](https://pkg.go.dev/github.com/fsnotify/fsnotify) and consult the [FAQ](#faq) for usage information.
## API stability
fsnotify is a fork of [howeyc/fsnotify](https://godoc.org/github.com/howeyc/fsnotify) with a new API as of v1.0. The API is based on [this design document](http://goo.gl/MrYxyA).
fsnotify is a fork of [howeyc/fsnotify](https://github.com/howeyc/fsnotify) with a new API as of v1.0. The API is based on [this design document](http://goo.gl/MrYxyA).
All [releases](https://github.com/fsnotify/fsnotify/releases) are tagged based on [Semantic Versioning](http://semver.org/). Further API changes are [planned](https://github.com/fsnotify/fsnotify/milestones), and will be tagged with a new major revision number.
Go 1.6 supports dependencies located in the `vendor/` folder. Unless you are creating a library, it is recommended that you copy fsnotify into `vendor/github.com/fsnotify/fsnotify` within your project, and likewise for `golang.org/x/sys`.
All [releases](https://github.com/fsnotify/fsnotify/releases) are tagged based on [Semantic Versioning](http://semver.org/).
## Usage
@ -84,10 +78,6 @@ func main() {
Please refer to [CONTRIBUTING][] before opening an issue or pull request.
## Example
See [example_test.go](https://github.com/fsnotify/fsnotify/blob/master/example_test.go).
## FAQ
**When a file is moved to another directory is it still being watched?**

View File

@ -0,0 +1,36 @@
// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !darwin && !dragonfly && !freebsd && !openbsd && !linux && !netbsd && !solaris && !windows
// +build !darwin,!dragonfly,!freebsd,!openbsd,!linux,!netbsd,!solaris,!windows
package fsnotify
import (
"fmt"
"runtime"
)
// Watcher watches a set of files, delivering events to a channel.
type Watcher struct{}
// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
func NewWatcher() (*Watcher, error) {
return nil, fmt.Errorf("fsnotify not supported on %s", runtime.GOOS)
}
// Close removes all watches and closes the events channel.
func (w *Watcher) Close() error {
return nil
}
// Add starts watching the named file or directory (non-recursively).
func (w *Watcher) Add(name string) error {
return nil
}
// Remove stops watching the the named file or directory (non-recursively).
func (w *Watcher) Remove(name string) error {
return nil
}

View File

@ -163,6 +163,19 @@ func (w *Watcher) Remove(name string) error {
return nil
}
// WatchList returns the directories and files that are being monitered.
func (w *Watcher) WatchList() []string {
w.mu.Lock()
defer w.mu.Unlock()
entries := make([]string, 0, len(w.watches))
for pathname := range w.watches {
entries = append(entries, pathname)
}
return entries
}
type watch struct {
wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall)
flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags)

View File

@ -38,7 +38,6 @@ func newFdPoller(fd int) (*fdPoller, error) {
poller.close()
}
}()
poller.fd = fd
// Create epoll fd
poller.epfd, errno = unix.EpollCreate1(unix.EPOLL_CLOEXEC)

View File

@ -148,6 +148,19 @@ func (w *Watcher) Remove(name string) error {
return nil
}
// WatchList returns the directories and files that are being monitered.
func (w *Watcher) WatchList() []string {
w.mu.Lock()
defer w.mu.Unlock()
entries := make([]string, 0, len(w.watches))
for pathname := range w.watches {
entries = append(entries, pathname)
}
return entries
}
// Watch all events (except NOTE_EXTEND, NOTE_LINK, NOTE_REVOKE)
const noteAllEvents = unix.NOTE_DELETE | unix.NOTE_WRITE | unix.NOTE_ATTRIB | unix.NOTE_RENAME

View File

@ -12,6 +12,7 @@ import (
"fmt"
"os"
"path/filepath"
"reflect"
"runtime"
"sync"
"syscall"
@ -96,6 +97,21 @@ func (w *Watcher) Remove(name string) error {
return <-in.reply
}
// WatchList returns the directories and files that are being monitered.
func (w *Watcher) WatchList() []string {
w.mu.Lock()
defer w.mu.Unlock()
entries := make([]string, 0, len(w.watches))
for _, entry := range w.watches {
for _, watchEntry := range entry {
entries = append(entries, watchEntry.path)
}
}
return entries
}
const (
// Options for AddWatch
sysFSONESHOT = 0x80000000
@ -452,8 +468,16 @@ func (w *Watcher) readEvents() {
// Point "raw" to the event in the buffer
raw := (*syscall.FileNotifyInformation)(unsafe.Pointer(&watch.buf[offset]))
buf := (*[syscall.MAX_PATH]uint16)(unsafe.Pointer(&raw.FileName))
name := syscall.UTF16ToString(buf[:raw.FileNameLength/2])
// TODO: Consider using unsafe.Slice that is available from go1.17
// https://stackoverflow.com/questions/51187973/how-to-create-an-array-or-a-slice-from-an-array-unsafe-pointer-in-golang
// instead of using a fixed syscall.MAX_PATH buf, we create a buf that is the size of the path name
size := int(raw.FileNameLength / 2)
var buf []uint16
sh := (*reflect.SliceHeader)(unsafe.Pointer(&buf))
sh.Data = uintptr(unsafe.Pointer(&raw.FileName))
sh.Len = size
sh.Cap = size
name := syscall.UTF16ToString(buf)
fullname := filepath.Join(watch.path, name)
var mask uint64

View File

@ -1,5 +1,5 @@
## locales
<img align="right" src="https://raw.githubusercontent.com/go-playground/locales/master/logo.png">![Project status](https://img.shields.io/badge/version-0.13.0-green.svg)
<img align="right" src="https://raw.githubusercontent.com/go-playground/locales/master/logo.png">![Project status](https://img.shields.io/badge/version-0.14.0-green.svg)
[![Build Status](https://travis-ci.org/go-playground/locales.svg?branch=master)](https://travis-ci.org/go-playground/locales)
[![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/locales)](https://goreportcard.com/report/github.com/go-playground/locales)
[![GoDoc](https://godoc.org/github.com/go-playground/locales?status.svg)](https://godoc.org/github.com/go-playground/locales)
@ -11,7 +11,7 @@ an i18n package; these were built for use with, but not exclusive to, [Universal
Features
--------
- [x] Rules generated from the latest [CLDR](http://cldr.unicode.org/index/downloads) data, v31.0.1
- [x] Rules generated from the latest [CLDR](http://cldr.unicode.org/index/downloads) data, v36.0.1
- [x] Contains Cardinal, Ordinal and Range Plural Rules
- [x] Contains Month, Weekday and Timezone translations built in
- [x] Contains Date & Time formatting functions

View File

@ -176,6 +176,7 @@ const (
MNT
MOP
MRO
MRU
MTL
MTP
MUR
@ -262,9 +263,11 @@ const (
UYI
UYP
UYU
UYW
UZS
VEB
VEF
VES
VND
VNN
VUV

View File

@ -0,0 +1,18 @@
GOCMD=GO111MODULE=on go
linters-install:
@golangci-lint --version >/dev/null 2>&1 || { \
echo "installing linting tools..."; \
curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s v1.41.1; \
}
lint: linters-install
golangci-lint run
test:
$(GOCMD) test -cover -race ./...
bench:
$(GOCMD) test -bench=. -benchmem ./...
.PHONY: test lint linters-install

View File

@ -1,5 +1,5 @@
## universal-translator
<img align="right" src="https://raw.githubusercontent.com/go-playground/universal-translator/master/logo.png">![Project status](https://img.shields.io/badge/version-0.17.0-green.svg)
<img align="right" src="https://raw.githubusercontent.com/go-playground/universal-translator/master/logo.png">![Project status](https://img.shields.io/badge/version-0.18.0-green.svg)
[![Build Status](https://travis-ci.org/go-playground/universal-translator.svg?branch=master)](https://travis-ci.org/go-playground/universal-translator)
[![Coverage Status](https://coveralls.io/repos/github/go-playground/universal-translator/badge.svg)](https://coveralls.io/github/go-playground/universal-translator)
[![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/universal-translator)](https://goreportcard.com/report/github.com/go-playground/universal-translator)
@ -18,7 +18,7 @@ use in your applications.
Features
--------
- [x] Rules generated from the [CLDR](http://cldr.unicode.org/index/downloads) data, v30.0.3
- [x] Rules generated from the [CLDR](http://cldr.unicode.org/index/downloads) data, v36.0.1
- [x] Contains Cardinal, Ordinal and Range Plural Rules
- [x] Contains Month, Weekday and Timezone translations built in
- [x] Contains Date & Time formatting functions
@ -51,7 +51,7 @@ Please see https://godoc.org/github.com/go-playground/universal-translator for u
File formatting
--------------
All types, Plain substitution, Cardinal, Ordinal and Range translations can all be contained withing the same file(s);
All types, Plain substitution, Cardinal, Ordinal and Range translations can all be contained within the same file(s);
they are only separated for easy viewing.
##### Examples:

View File

@ -257,6 +257,8 @@ func (t *UniversalTranslator) ImportByReader(format ImportExportFormat, reader i
func stringToPR(s string) locales.PluralRule {
switch s {
case "Zero":
return locales.PluralRuleZero
case "One":
return locales.PluralRuleOne
case "Two":

View File

@ -159,13 +159,13 @@ func (t *translator) AddCardinal(key interface{}, text string, rule locales.Plur
}
} else {
tarr = make([]*transText, 7, 7)
tarr = make([]*transText, 7)
t.cardinalTanslations[key] = tarr
}
trans := &transText{
text: text,
indexes: make([]int, 2, 2),
indexes: make([]int, 2),
}
tarr[rule] = trans
@ -211,13 +211,13 @@ func (t *translator) AddOrdinal(key interface{}, text string, rule locales.Plura
}
} else {
tarr = make([]*transText, 7, 7)
tarr = make([]*transText, 7)
t.ordinalTanslations[key] = tarr
}
trans := &transText{
text: text,
indexes: make([]int, 2, 2),
indexes: make([]int, 2),
}
tarr[rule] = trans
@ -261,13 +261,13 @@ func (t *translator) AddRange(key interface{}, text string, rule locales.PluralR
}
} else {
tarr = make([]*transText, 7, 7)
tarr = make([]*transText, 7)
t.rangeTanslations[key] = tarr
}
trans := &transText{
text: text,
indexes: make([]int, 4, 4),
indexes: make([]int, 4),
}
tarr[rule] = trans

View File

@ -1,50 +0,0 @@
dist: bionic
language: go
go_import_path: github.com/godbus/dbus
go:
- 1.11.x
- 1.12.x
- 1.13.x
- tip
matrix:
fast_finish: true
allow_failures:
- go: tip
addons:
apt:
packages:
- dbus
- dbus-x11
before_install:
- export GO111MODULE=on
script:
- go test -v -race -mod=readonly ./... # Run all the tests with the race detector enabled
- go vet ./... # go vet is the official Go static analyzer
jobs:
include:
# The build matrix doesn't cover build stages, so manually expand
# the jobs with anchors
- &multiarch
stage: "Multiarch Test"
go: 1.11.x
env: TARGETS="386 arm arm64 ppc64le"
before_install:
- docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
script:
- |
set -e
for target in $TARGETS; do
printf "\e[1mRunning test suite under ${target}.\e[0m\n"
GOARCH="$target" go test -v ./...
printf "\n\n"
done
- <<: *multiarch
go: 1.12.x
- <<: *multiarch
go: 1.13.x

View File

@ -1,4 +1,4 @@
[![Build Status](https://travis-ci.org/godbus/dbus.svg?branch=master)](https://travis-ci.org/godbus/dbus)
![Build Status](https://github.com/godbus/dbus/workflows/Go/badge.svg)
dbus
----
@ -14,14 +14,12 @@ D-Bus message bus system.
### Installation
This packages requires Go 1.7. If you installed it and set up your GOPATH, just run:
This packages requires Go 1.12 or later. It can be installed by running the command below:
```
go get github.com/godbus/dbus
go get github.com/godbus/dbus/v5
```
If you want to use the subpackages, you can install them the same way.
### Usage
The complete package documentation and some simple examples are available at
@ -30,8 +28,12 @@ The complete package documentation and some simple examples are available at
gives a short overview over the basic usage.
#### Projects using godbus
- [notify](https://github.com/esiqveland/notify) provides desktop notifications over dbus into a library.
- [fyne](https://github.com/fyne-io/fyne) a cross platform GUI in Go inspired by Material Design.
- [fynedesk](https://github.com/fyne-io/fynedesk) a full desktop environment for Linux/Unix using Fyne.
- [go-bluetooth](https://github.com/muka/go-bluetooth) provides a bluetooth client over bluez dbus API.
- [iwd](https://github.com/shibumi/iwd) go bindings for the internet wireless daemon "iwd".
- [notify](https://github.com/esiqveland/notify) provides desktop notifications over dbus into a library.
- [playerbm](https://github.com/altdesktop/playerbm) a bookmark utility for media players.
Please note that the API is considered unstable for now and may change without
further notice.

View File

@ -37,7 +37,7 @@ const (
// Auth defines the behaviour of an authentication mechanism.
type Auth interface {
// Return the name of the mechnism, the argument to the first AUTH command
// Return the name of the mechanism, the argument to the first AUTH command
// and the next status.
FirstData() (name, resp []byte, status AuthStatus)
@ -53,7 +53,7 @@ type Auth interface {
// bus. Auth must not be called on shared connections.
func (conn *Conn) Auth(methods []Auth) error {
if methods == nil {
uid := strconv.Itoa(os.Getuid())
uid := strconv.Itoa(os.Geteuid())
methods = []Auth{AuthExternal(uid), AuthCookieSha1(uid, getHomeDir())}
}
in := bufio.NewReader(conn.transport)
@ -75,9 +75,9 @@ func (conn *Conn) Auth(methods []Auth) error {
s = s[1:]
for _, v := range s {
for _, m := range methods {
if name, data, status := m.FirstData(); bytes.Equal(v, name) {
if name, _, status := m.FirstData(); bytes.Equal(v, name) {
var ok bool
err = authWriteLine(conn.transport, []byte("AUTH"), v, data)
err = authWriteLine(conn.transport, []byte("AUTH"), v)
if err != nil {
return err
}
@ -176,9 +176,10 @@ func (conn *Conn) tryAuth(m Auth, state authState, in *bufio.Reader) (error, boo
return err, false
}
state = waitingForReject
} else {
conn.uuid = string(s[1])
return nil, true
}
conn.uuid = string(s[1])
return nil, true
case state == waitingForData:
err = authWriteLine(conn.transport, []byte("ERROR"))
if err != nil {
@ -191,14 +192,18 @@ func (conn *Conn) tryAuth(m Auth, state authState, in *bufio.Reader) (error, boo
return err, false
}
state = waitingForReject
} else {
conn.uuid = string(s[1])
return nil, true
}
case state == waitingForOk && string(s[0]) == "DATA":
err = authWriteLine(conn.transport, []byte("DATA"))
if err != nil {
return err, false
}
conn.uuid = string(s[1])
return nil, true
case state == waitingForOk && string(s[0]) == "REJECTED":
return nil, false
case state == waitingForOk && (string(s[0]) == "DATA" ||
string(s[0]) == "ERROR"):
case state == waitingForOk && string(s[0]) == "ERROR":
err = authWriteLine(conn.transport, []byte("CANCEL"))
if err != nil {
return err, false

View File

@ -24,6 +24,15 @@ type Call struct {
// Holds the response once the call is done.
Body []interface{}
// ResponseSequence stores the sequence number of the DBus message containing
// the call response (or error). This can be compared to the sequence number
// of other call responses and signals on this connection to determine their
// relative ordering on the underlying DBus connection.
// For errors, ResponseSequence is populated only if the error came from a
// DBusMessage that was received or if there was an error receiving. In case of
// failure to make the call, ResponseSequence will be NoSequence.
ResponseSequence Sequence
// tracks context and canceler
ctx context.Context
ctxCanceler context.CancelFunc

View File

@ -45,6 +45,7 @@ type Conn struct {
serialGen SerialGenerator
inInt Interceptor
outInt Interceptor
auth []Auth
names *nameTracker
calls *callTracker
@ -59,7 +60,8 @@ type Conn struct {
func SessionBus() (conn *Conn, err error) {
sessionBusLck.Lock()
defer sessionBusLck.Unlock()
if sessionBus != nil {
if sessionBus != nil &&
sessionBus.Connected() {
return sessionBus, nil
}
defer func() {
@ -67,23 +69,11 @@ func SessionBus() (conn *Conn, err error) {
sessionBus = conn
}
}()
conn, err = SessionBusPrivate()
if err != nil {
return
}
if err = conn.Auth(nil); err != nil {
conn.Close()
conn = nil
return
}
if err = conn.Hello(); err != nil {
conn.Close()
conn = nil
}
conn, err = ConnectSessionBus()
return
}
func getSessionBusAddress() (string, error) {
func getSessionBusAddress(autolaunch bool) (string, error) {
if address := os.Getenv("DBUS_SESSION_BUS_ADDRESS"); address != "" && address != "autolaunch:" {
return address, nil
@ -91,12 +81,26 @@ func getSessionBusAddress() (string, error) {
os.Setenv("DBUS_SESSION_BUS_ADDRESS", address)
return address, nil
}
if !autolaunch {
return "", errors.New("dbus: couldn't determine address of session bus")
}
return getSessionBusPlatformAddress()
}
// SessionBusPrivate returns a new private connection to the session bus.
func SessionBusPrivate(opts ...ConnOption) (*Conn, error) {
address, err := getSessionBusAddress()
address, err := getSessionBusAddress(true)
if err != nil {
return nil, err
}
return Dial(address, opts...)
}
// SessionBusPrivate returns a new private connection to the session bus. If
// the session bus is not already open, do not attempt to launch it.
func SessionBusPrivateNoAutoStartup(opts ...ConnOption) (*Conn, error) {
address, err := getSessionBusAddress(false)
if err != nil {
return nil, err
}
@ -116,7 +120,8 @@ func SessionBusPrivateHandler(handler Handler, signalHandler SignalHandler) (*Co
func SystemBus() (conn *Conn, err error) {
systemBusLck.Lock()
defer systemBusLck.Unlock()
if systemBus != nil {
if systemBus != nil &&
systemBus.Connected() {
return systemBus, nil
}
defer func() {
@ -124,25 +129,47 @@ func SystemBus() (conn *Conn, err error) {
systemBus = conn
}
}()
conn, err = SystemBusPrivate()
conn, err = ConnectSystemBus()
return
}
// ConnectSessionBus connects to the session bus.
func ConnectSessionBus(opts ...ConnOption) (*Conn, error) {
address, err := getSessionBusAddress(true)
if err != nil {
return
return nil, err
}
if err = conn.Auth(nil); err != nil {
conn.Close()
conn = nil
return
return Connect(address, opts...)
}
// ConnectSystemBus connects to the system bus.
func ConnectSystemBus(opts ...ConnOption) (*Conn, error) {
return Connect(getSystemBusPlatformAddress(), opts...)
}
// Connect connects to the given address.
//
// Returned connection is ready to use and doesn't require calling
// Auth and Hello methods to make it usable.
func Connect(address string, opts ...ConnOption) (*Conn, error) {
conn, err := Dial(address, opts...)
if err != nil {
return nil, err
}
if err = conn.Auth(conn.auth); err != nil {
_ = conn.Close()
return nil, err
}
if err = conn.Hello(); err != nil {
conn.Close()
conn = nil
_ = conn.Close()
return nil, err
}
return
return conn, nil
}
// SystemBusPrivate returns a new private connection to the system bus.
// Note: this connection is not ready to use. One must perform Auth and Hello
// on the connection before it is useable.
// on the connection before it is usable.
func SystemBusPrivate(opts ...ConnOption) (*Conn, error) {
return Dial(getSystemBusPlatformAddress(), opts...)
}
@ -167,7 +194,7 @@ func Dial(address string, opts ...ConnOption) (*Conn, error) {
//
// Deprecated: use Dial with options instead.
func DialHandler(address string, handler Handler, signalHandler SignalHandler) (*Conn, error) {
return Dial(address, WithSignalHandler(signalHandler))
return Dial(address, WithHandler(handler), WithSignalHandler(signalHandler))
}
// ConnOption is a connection option.
@ -197,6 +224,14 @@ func WithSerialGenerator(gen SerialGenerator) ConnOption {
}
}
// WithAuth sets authentication methods for the auth conversation.
func WithAuth(methods ...Auth) ConnOption {
return func(conn *Conn) error {
conn.auth = methods
return nil
}
}
// Interceptor intercepts incoming and outgoing messages.
type Interceptor func(msg *Message)
@ -249,10 +284,6 @@ func newConn(tr transport, opts ...ConnOption) (*Conn, error) {
conn.ctx = context.Background()
}
conn.ctx, conn.cancelCtx = context.WithCancel(conn.ctx)
go func() {
<-conn.ctx.Done()
conn.Close()
}()
conn.calls = newCallTracker()
if conn.handler == nil {
@ -267,6 +298,11 @@ func newConn(tr transport, opts ...ConnOption) (*Conn, error) {
conn.outHandler = &outputHandler{conn: conn}
conn.names = newNameTracker()
conn.busObj = conn.Object("org.freedesktop.DBus", "/org/freedesktop/DBus")
go func() {
<-conn.ctx.Done()
conn.Close()
}()
return conn, nil
}
@ -309,6 +345,11 @@ func (conn *Conn) Context() context.Context {
return conn.ctx
}
// Connected returns whether conn is connected
func (conn *Conn) Connected() bool {
return conn.ctx.Err() == nil
}
// Eavesdrop causes conn to send all incoming messages to the given channel
// without further processing. Method replies, errors and signals will not be
// sent to the appropriate channels and method calls will not be handled. If nil
@ -342,8 +383,9 @@ func (conn *Conn) Hello() error {
}
// inWorker runs in an own goroutine, reading incoming messages from the
// transport and dispatching them appropiately.
// transport and dispatching them appropriately.
func (conn *Conn) inWorker() {
sequenceGen := newSequenceGenerator()
for {
msg, err := conn.ReadMessage()
if err != nil {
@ -352,7 +394,7 @@ func (conn *Conn) inWorker() {
// anything but to shut down all stuff and returns errors to all
// pending replies.
conn.Close()
conn.calls.finalizeAllWithError(err)
conn.calls.finalizeAllWithError(sequenceGen, err)
return
}
// invalid messages are ignored
@ -381,13 +423,14 @@ func (conn *Conn) inWorker() {
if conn.inInt != nil {
conn.inInt(msg)
}
sequence := sequenceGen.next()
switch msg.Type {
case TypeError:
conn.serialGen.RetireSerial(conn.calls.handleDBusError(msg))
conn.serialGen.RetireSerial(conn.calls.handleDBusError(sequence, msg))
case TypeMethodReply:
conn.serialGen.RetireSerial(conn.calls.handleReply(msg))
conn.serialGen.RetireSerial(conn.calls.handleReply(sequence, msg))
case TypeSignal:
conn.handleSignal(msg)
conn.handleSignal(sequence, msg)
case TypeMethodCall:
go conn.handleCall(msg)
}
@ -395,7 +438,7 @@ func (conn *Conn) inWorker() {
}
}
func (conn *Conn) handleSignal(msg *Message) {
func (conn *Conn) handleSignal(sequence Sequence, msg *Message) {
iface := msg.Headers[FieldInterface].value.(string)
member := msg.Headers[FieldMember].value.(string)
// as per http://dbus.freedesktop.org/doc/dbus-specification.html ,
@ -421,10 +464,11 @@ func (conn *Conn) handleSignal(msg *Message) {
}
}
signal := &Signal{
Sender: sender,
Path: msg.Headers[FieldPath].value.(ObjectPath),
Name: iface + "." + member,
Body: msg.Body,
Sender: sender,
Path: msg.Headers[FieldPath].value.(ObjectPath),
Name: iface + "." + member,
Body: msg.Body,
Sequence: sequence,
}
conn.signalHandler.DeliverSignal(iface, member, signal)
}
@ -442,18 +486,31 @@ func (conn *Conn) Object(dest string, path ObjectPath) BusObject {
}
func (conn *Conn) sendMessageAndIfClosed(msg *Message, ifClosed func()) {
if msg.serial == 0 {
msg.serial = conn.getSerial()
}
if conn.outInt != nil {
conn.outInt(msg)
}
err := conn.outHandler.sendAndIfClosed(msg, ifClosed)
conn.calls.handleSendError(msg, err)
if err != nil {
conn.serialGen.RetireSerial(msg.serial)
conn.handleSendError(msg, err)
} else if msg.Type != TypeMethodCall {
conn.serialGen.RetireSerial(msg.serial)
}
}
func (conn *Conn) handleSendError(msg *Message, err error) {
if msg.Type == TypeMethodCall {
conn.calls.handleSendError(msg, err)
} else if msg.Type == TypeMethodReply {
if _, ok := err.(FormatError); ok {
conn.sendError(err, msg.Headers[FieldDestination].value.(string), msg.Headers[FieldReplySerial].value.(uint32))
}
}
conn.serialGen.RetireSerial(msg.serial)
}
// Send sends the given message to the message bus. You usually don't need to
// use this; use the higher-level equivalents (Call / Go, Emit and Export)
// instead. If msg is a method call and NoReplyExpected is not set, a non-nil
@ -473,16 +530,16 @@ func (conn *Conn) send(ctx context.Context, msg *Message, ch chan *Call) *Call {
if ctx == nil {
panic("nil context")
}
if ch == nil {
ch = make(chan *Call, 1)
} else if cap(ch) == 0 {
panic("dbus: unbuffered channel passed to (*Conn).Send")
}
var call *Call
ctx, canceler := context.WithCancel(ctx)
msg.serial = conn.getSerial()
if msg.Type == TypeMethodCall && msg.Flags&FlagNoReplyExpected == 0 {
if ch == nil {
ch = make(chan *Call, 5)
} else if cap(ch) == 0 {
panic("dbus: unbuffered channel passed to (*Conn).Send")
}
call = new(Call)
call.Destination, _ = msg.Headers[FieldDestination].value.(string)
call.Path, _ = msg.Headers[FieldPath].value.(ObjectPath)
@ -494,6 +551,11 @@ func (conn *Conn) send(ctx context.Context, msg *Message, ch chan *Call) *Call {
call.ctx = ctx
call.ctxCanceler = canceler
conn.calls.track(msg.serial, call)
if ctx.Err() != nil {
// short path: don't even send the message if context already cancelled
conn.calls.handleSendError(msg, ctx.Err())
return call
}
go func() {
<-ctx.Done()
conn.calls.handleSendError(msg, ctx.Err())
@ -504,7 +566,8 @@ func (conn *Conn) send(ctx context.Context, msg *Message, ch chan *Call) *Call {
})
} else {
canceler()
call = &Call{Err: nil}
call = &Call{Err: nil, Done: ch}
ch <- call
conn.sendMessageAndIfClosed(msg, func() {
call = &Call{Err: ErrClosed}
})
@ -529,7 +592,6 @@ func (conn *Conn) sendError(err error, dest string, serial uint32) {
}
msg := new(Message)
msg.Type = TypeError
msg.serial = conn.getSerial()
msg.Headers = make(map[HeaderField]Variant)
if dest != "" {
msg.Headers[FieldDestination] = MakeVariant(dest)
@ -548,7 +610,6 @@ func (conn *Conn) sendError(err error, dest string, serial uint32) {
func (conn *Conn) sendReply(dest string, serial uint32, values ...interface{}) {
msg := new(Message)
msg.Type = TypeMethodReply
msg.serial = conn.getSerial()
msg.Headers = make(map[HeaderField]Variant)
if dest != "" {
msg.Headers[FieldDestination] = MakeVariant(dest)
@ -564,8 +625,14 @@ func (conn *Conn) sendReply(dest string, serial uint32, values ...interface{}) {
// AddMatchSignal registers the given match rule to receive broadcast
// signals based on their contents.
func (conn *Conn) AddMatchSignal(options ...MatchOption) error {
return conn.AddMatchSignalContext(context.Background(), options...)
}
// AddMatchSignalContext acts like AddMatchSignal but takes a context.
func (conn *Conn) AddMatchSignalContext(ctx context.Context, options ...MatchOption) error {
options = append([]MatchOption{withMatchType("signal")}, options...)
return conn.busObj.Call(
return conn.busObj.CallWithContext(
ctx,
"org.freedesktop.DBus.AddMatch", 0,
formatMatchOptions(options),
).Store()
@ -573,8 +640,14 @@ func (conn *Conn) AddMatchSignal(options ...MatchOption) error {
// RemoveMatchSignal removes the first rule that matches previously registered with AddMatchSignal.
func (conn *Conn) RemoveMatchSignal(options ...MatchOption) error {
return conn.RemoveMatchSignalContext(context.Background(), options...)
}
// RemoveMatchSignalContext acts like RemoveMatchSignal but takes a context.
func (conn *Conn) RemoveMatchSignalContext(ctx context.Context, options ...MatchOption) error {
options = append([]MatchOption{withMatchType("signal")}, options...)
return conn.busObj.Call(
return conn.busObj.CallWithContext(
ctx,
"org.freedesktop.DBus.RemoveMatch", 0,
formatMatchOptions(options),
).Store()
@ -582,7 +655,9 @@ func (conn *Conn) RemoveMatchSignal(options ...MatchOption) error {
// Signal registers the given channel to be passed all received signal messages.
//
// Multiple of these channels can be registered at the same time.
// Multiple of these channels can be registered at the same time. The channel is
// closed if the Conn is closed; it should not be closed by the caller before
// RemoveSignal was called on it.
//
// These channels are "overwritten" by Eavesdrop; i.e., if there currently is a
// channel for eavesdropped messages, this channel receives all signals, and
@ -639,10 +714,11 @@ func (e Error) Error() string {
// Signal represents a D-Bus message of type Signal. The name member is given in
// "interface.member" notation, e.g. org.freedesktop.D-Bus.NameLost.
type Signal struct {
Sender string
Path ObjectPath
Name string
Body []interface{}
Sender string
Path ObjectPath
Name string
Body []interface{}
Sequence Sequence
}
// transport is a D-Bus transport.
@ -697,7 +773,12 @@ func getKey(s, key string) string {
for _, keyEqualsValue := range strings.Split(s, ",") {
keyValue := strings.SplitN(keyEqualsValue, "=", 2)
if len(keyValue) == 2 && keyValue[0] == key {
return keyValue[1]
val, err := UnescapeBusAddressValue(keyValue[1])
if err != nil {
// No way to return an error.
return ""
}
return val
}
}
return ""
@ -825,25 +906,25 @@ func (tracker *callTracker) track(sn uint32, call *Call) {
tracker.lck.Unlock()
}
func (tracker *callTracker) handleReply(msg *Message) uint32 {
func (tracker *callTracker) handleReply(sequence Sequence, msg *Message) uint32 {
serial := msg.Headers[FieldReplySerial].value.(uint32)
tracker.lck.RLock()
_, ok := tracker.calls[serial]
tracker.lck.RUnlock()
if ok {
tracker.finalizeWithBody(serial, msg.Body)
tracker.finalizeWithBody(serial, sequence, msg.Body)
}
return serial
}
func (tracker *callTracker) handleDBusError(msg *Message) uint32 {
func (tracker *callTracker) handleDBusError(sequence Sequence, msg *Message) uint32 {
serial := msg.Headers[FieldReplySerial].value.(uint32)
tracker.lck.RLock()
_, ok := tracker.calls[serial]
tracker.lck.RUnlock()
if ok {
name, _ := msg.Headers[FieldErrorName].value.(string)
tracker.finalizeWithError(serial, Error{name, msg.Body})
tracker.finalizeWithError(serial, sequence, Error{name, msg.Body})
}
return serial
}
@ -856,7 +937,7 @@ func (tracker *callTracker) handleSendError(msg *Message, err error) {
_, ok := tracker.calls[msg.serial]
tracker.lck.RUnlock()
if ok {
tracker.finalizeWithError(msg.serial, err)
tracker.finalizeWithError(msg.serial, NoSequence, err)
}
}
@ -871,7 +952,7 @@ func (tracker *callTracker) finalize(sn uint32) {
}
}
func (tracker *callTracker) finalizeWithBody(sn uint32, body []interface{}) {
func (tracker *callTracker) finalizeWithBody(sn uint32, sequence Sequence, body []interface{}) {
tracker.lck.Lock()
c, ok := tracker.calls[sn]
if ok {
@ -880,11 +961,12 @@ func (tracker *callTracker) finalizeWithBody(sn uint32, body []interface{}) {
tracker.lck.Unlock()
if ok {
c.Body = body
c.ResponseSequence = sequence
c.done()
}
}
func (tracker *callTracker) finalizeWithError(sn uint32, err error) {
func (tracker *callTracker) finalizeWithError(sn uint32, sequence Sequence, err error) {
tracker.lck.Lock()
c, ok := tracker.calls[sn]
if ok {
@ -893,11 +975,12 @@ func (tracker *callTracker) finalizeWithError(sn uint32, err error) {
tracker.lck.Unlock()
if ok {
c.Err = err
c.ResponseSequence = sequence
c.done()
}
}
func (tracker *callTracker) finalizeAllWithError(err error) {
func (tracker *callTracker) finalizeAllWithError(sequenceGen *sequenceGenerator, err error) {
tracker.lck.Lock()
closedCalls := make([]*Call, 0, len(tracker.calls))
for sn := range tracker.calls {
@ -907,6 +990,7 @@ func (tracker *callTracker) finalizeAllWithError(err error) {
tracker.lck.Unlock()
for _, call := range closedCalls {
call.Err = err
call.ResponseSequence = sequenceGen.next()
call.done()
}
}

View File

@ -54,7 +54,7 @@ func tryDiscoverDbusSessionBusAddress() string {
if runUserBusFile := path.Join(runtimeDirectory, "bus"); fileExists(runUserBusFile) {
// if /run/user/<uid>/bus exists, that file itself
// *is* the unix socket, so return its path
return fmt.Sprintf("unix:path=%s", runUserBusFile)
return fmt.Sprintf("unix:path=%s", EscapeBusAddressValue(runUserBusFile))
}
if runUserSessionDbusFile := path.Join(runtimeDirectory, "dbus-session"); fileExists(runUserSessionDbusFile) {
// if /run/user/<uid>/dbus-session exists, it's a
@ -85,9 +85,6 @@ func getRuntimeDirectory() (string, error) {
}
func fileExists(filename string) bool {
if _, err := os.Stat(filename); !os.IsNotExist(err) {
return true
} else {
return false
}
_, err := os.Stat(filename)
return !os.IsNotExist(err)
}

View File

@ -28,6 +28,7 @@ var (
interfaceType = reflect.TypeOf((*interface{})(nil)).Elem()
unixFDType = reflect.TypeOf(UnixFD(0))
unixFDIndexType = reflect.TypeOf(UnixFDIndex(0))
errType = reflect.TypeOf((*error)(nil)).Elem()
)
// An InvalidTypeError signals that a value which cannot be represented in the
@ -63,6 +64,9 @@ func storeInterfaces(src, dest interface{}) error {
func store(dest, src reflect.Value) error {
if dest.Kind() == reflect.Ptr {
if dest.IsNil() {
dest.Set(reflect.New(dest.Type().Elem()))
}
return store(dest.Elem(), src)
}
switch src.Kind() {
@ -118,8 +122,11 @@ func isConvertibleTo(dest, src reflect.Type) bool {
case dest.Kind() == reflect.Slice:
return src.Kind() == reflect.Slice &&
isConvertibleTo(dest.Elem(), src.Elem())
case dest.Kind() == reflect.Ptr:
dest = dest.Elem()
return isConvertibleTo(dest, src)
case dest.Kind() == reflect.Struct:
return src == interfacesType
return src == interfacesType || dest.Kind() == src.Kind()
default:
return src.ConvertibleTo(dest)
}
@ -270,13 +277,8 @@ func storeSliceIntoInterface(dest, src reflect.Value) error {
func storeSliceIntoSlice(dest, src reflect.Value) error {
if dest.IsNil() || dest.Len() < src.Len() {
dest.Set(reflect.MakeSlice(dest.Type(), src.Len(), src.Cap()))
}
if dest.Len() != src.Len() {
return fmt.Errorf(
"dbus.Store: type mismatch: "+
"slices are different lengths "+
"need: %d have: %d",
src.Len(), dest.Len())
} else if dest.Len() > src.Len() {
dest.Set(dest.Slice(0, src.Len()))
}
for i := 0; i < src.Len(); i++ {
err := store(dest.Index(i), getVariantValue(src.Index(i)))

View File

@ -10,14 +10,16 @@ type decoder struct {
in io.Reader
order binary.ByteOrder
pos int
fds []int
}
// newDecoder returns a new decoder that reads values from in. The input is
// expected to be in the given byte order.
func newDecoder(in io.Reader, order binary.ByteOrder) *decoder {
func newDecoder(in io.Reader, order binary.ByteOrder, fds []int) *decoder {
dec := new(decoder)
dec.in = in
dec.order = order
dec.fds = fds
return dec
}
@ -53,7 +55,7 @@ func (dec *decoder) Decode(sig Signature) (vs []interface{}, err error) {
vs = make([]interface{}, 0)
s := sig.str
for s != "" {
err, rem := validSingle(s, 0)
err, rem := validSingle(s, &depthCounter{})
if err != nil {
return nil, err
}
@ -150,7 +152,7 @@ func (dec *decoder) decode(s string, depth int) interface{} {
if len(sig.str) == 0 {
panic(FormatError("variant signature is empty"))
}
err, rem := validSingle(sig.str, 0)
err, rem := validSingle(sig.str, &depthCounter{})
if err != nil {
panic(err)
}
@ -161,7 +163,11 @@ func (dec *decoder) decode(s string, depth int) interface{} {
variant.value = dec.decode(sig.str, depth+1)
return variant
case 'h':
return UnixFDIndex(dec.decode("u", depth).(uint32))
idx := dec.decode("u", depth).(uint32)
if int(idx) < len(dec.fds) {
return UnixFD(dec.fds[idx])
}
return UnixFDIndex(idx)
case 'a':
if len(s) > 1 && s[1] == '{' {
ksig := s[2:3]
@ -219,7 +225,7 @@ func (dec *decoder) decode(s string, depth int) interface{} {
v := make([]interface{}, 0)
s = s[1 : len(s)-1]
for s != "" {
err, rem := validSingle(s, 0)
err, rem := validSingle(s, &depthCounter{})
if err != nil {
panic(err)
}

View File

@ -126,14 +126,28 @@ func (m exportedMethod) Call(args ...interface{}) ([]interface{}, error) {
}
ret := m.Value.Call(params)
err := ret[t.NumOut()-1].Interface().(*Error)
ret = ret[:t.NumOut()-1]
var err error
nilErr := false // The reflection will find almost-nils, let's only pass back clean ones!
if t.NumOut() > 0 {
if e, ok := ret[t.NumOut()-1].Interface().(*Error); ok { // godbus *Error
nilErr = ret[t.NumOut()-1].IsNil()
ret = ret[:t.NumOut()-1]
err = e
} else if ret[t.NumOut()-1].Type().Implements(errType) { // Go error
i := ret[t.NumOut()-1].Interface()
if i == nil {
nilErr = ret[t.NumOut()-1].IsNil()
} else {
err = i.(error)
}
ret = ret[:t.NumOut()-1]
}
}
out := make([]interface{}, len(ret))
for i, val := range ret {
out[i] = val.Interface()
}
if err == nil {
if nilErr || err == nil {
//concrete type to interface nil is a special case
return out, nil
}

View File

@ -10,8 +10,10 @@ value.
Conversion Rules
For outgoing messages, Go types are automatically converted to the
corresponding D-Bus types. The following types are directly encoded as their
respective D-Bus equivalents:
corresponding D-Bus types. See the official specification at
https://dbus.freedesktop.org/doc/dbus-specification.html#type-system for more
information on the D-Bus type system. The following types are directly encoded
as their respective D-Bus equivalents:
Go type | D-Bus type
------------+-----------
@ -39,8 +41,8 @@ Maps encode as DICTs, provided that their key type can be used as a key for
a DICT.
Structs other than Variant and Signature encode as a STRUCT containing their
exported fields. Fields whose tags contain `dbus:"-"` and unexported fields will
be skipped.
exported fields in order. Fields whose tags contain `dbus:"-"` and unexported
fields will be skipped.
Pointers encode as the value they're pointed to.

View File

@ -5,28 +5,33 @@ import (
"encoding/binary"
"io"
"reflect"
"strings"
"unicode/utf8"
)
// An encoder encodes values to the D-Bus wire format.
type encoder struct {
out io.Writer
fds []int
order binary.ByteOrder
pos int
}
// NewEncoder returns a new encoder that writes to out in the given byte order.
func newEncoder(out io.Writer, order binary.ByteOrder) *encoder {
return newEncoderAtOffset(out, 0, order)
func newEncoder(out io.Writer, order binary.ByteOrder, fds []int) *encoder {
enc := newEncoderAtOffset(out, 0, order, fds)
return enc
}
// newEncoderAtOffset returns a new encoder that writes to out in the given
// byte order. Specify the offset to initialize pos for proper alignment
// computation.
func newEncoderAtOffset(out io.Writer, offset int, order binary.ByteOrder) *encoder {
func newEncoderAtOffset(out io.Writer, offset int, order binary.ByteOrder, fds []int) *encoder {
enc := new(encoder)
enc.out = out
enc.order = order
enc.pos = offset
enc.fds = fds
return enc
}
@ -75,6 +80,9 @@ func (enc *encoder) Encode(vs ...interface{}) (err error) {
// encode encodes the given value to the writer and panics on error. depth holds
// the depth of the container nesting.
func (enc *encoder) encode(v reflect.Value, depth int) {
if depth > 64 {
panic(FormatError("input exceeds depth limitation"))
}
enc.align(alignment(v.Type()))
switch v.Kind() {
case reflect.Uint8:
@ -97,7 +105,14 @@ func (enc *encoder) encode(v reflect.Value, depth int) {
enc.binwrite(uint16(v.Uint()))
enc.pos += 2
case reflect.Int, reflect.Int32:
enc.binwrite(int32(v.Int()))
if v.Type() == unixFDType {
fd := v.Int()
idx := len(enc.fds)
enc.fds = append(enc.fds, int(fd))
enc.binwrite(uint32(idx))
} else {
enc.binwrite(int32(v.Int()))
}
enc.pos += 4
case reflect.Uint, reflect.Uint32:
enc.binwrite(uint32(v.Uint()))
@ -112,9 +127,21 @@ func (enc *encoder) encode(v reflect.Value, depth int) {
enc.binwrite(v.Float())
enc.pos += 8
case reflect.String:
enc.encode(reflect.ValueOf(uint32(len(v.String()))), depth)
str := v.String()
if !utf8.ValidString(str) {
panic(FormatError("input has a not-utf8 char in string"))
}
if strings.IndexByte(str, byte(0)) != -1 {
panic(FormatError("input has a null char('\\000') in string"))
}
if v.Type() == objectPathType {
if !ObjectPath(str).IsValid() {
panic(FormatError("invalid object path"))
}
}
enc.encode(reflect.ValueOf(uint32(len(str))), depth)
b := make([]byte, v.Len()+1)
copy(b, v.String())
copy(b, str)
b[len(b)-1] = 0
n, err := enc.out.Write(b)
if err != nil {
@ -124,20 +151,23 @@ func (enc *encoder) encode(v reflect.Value, depth int) {
case reflect.Ptr:
enc.encode(v.Elem(), depth)
case reflect.Slice, reflect.Array:
if depth >= 64 {
panic(FormatError("input exceeds container depth limit"))
}
// Lookahead offset: 4 bytes for uint32 length (with alignment),
// plus alignment for elements.
n := enc.padding(0, 4) + 4
offset := enc.pos + n + enc.padding(n, alignment(v.Type().Elem()))
var buf bytes.Buffer
bufenc := newEncoderAtOffset(&buf, offset, enc.order)
bufenc := newEncoderAtOffset(&buf, offset, enc.order, enc.fds)
for i := 0; i < v.Len(); i++ {
bufenc.encode(v.Index(i), depth+1)
}
if buf.Len() > 1<<26 {
panic(FormatError("input exceeds array size limitation"))
}
enc.fds = bufenc.fds
enc.encode(reflect.ValueOf(uint32(buf.Len())), depth)
length := buf.Len()
enc.align(alignment(v.Type().Elem()))
@ -146,13 +176,10 @@ func (enc *encoder) encode(v reflect.Value, depth int) {
}
enc.pos += length
case reflect.Struct:
if depth >= 64 && v.Type() != signatureType {
panic(FormatError("input exceeds container depth limit"))
}
switch t := v.Type(); t {
case signatureType:
str := v.Field(0)
enc.encode(reflect.ValueOf(byte(str.Len())), depth+1)
enc.encode(reflect.ValueOf(byte(str.Len())), depth)
b := make([]byte, str.Len()+1)
copy(b, str.String())
b[len(b)-1] = 0
@ -176,9 +203,6 @@ func (enc *encoder) encode(v reflect.Value, depth int) {
case reflect.Map:
// Maps are arrays of structures, so they actually increase the depth by
// 2.
if depth >= 63 {
panic(FormatError("input exceeds container depth limit"))
}
if !isKeyType(v.Type().Key()) {
panic(InvalidTypeError{v.Type()})
}
@ -189,12 +213,13 @@ func (enc *encoder) encode(v reflect.Value, depth int) {
offset := enc.pos + n + enc.padding(n, 8)
var buf bytes.Buffer
bufenc := newEncoderAtOffset(&buf, offset, enc.order)
bufenc := newEncoderAtOffset(&buf, offset, enc.order, enc.fds)
for _, k := range keys {
bufenc.align(8)
bufenc.encode(k, depth+2)
bufenc.encode(v.MapIndex(k), depth+2)
}
enc.fds = bufenc.fds
enc.encode(reflect.ValueOf(uint32(buf.Len())), depth)
length := buf.Len()
enc.align(8)

84
vendor/github.com/godbus/dbus/v5/escape.go generated vendored Normal file
View File

@ -0,0 +1,84 @@
package dbus
import "net/url"
// EscapeBusAddressValue implements a requirement to escape the values
// in D-Bus server addresses, as defined by the D-Bus specification at
// https://dbus.freedesktop.org/doc/dbus-specification.html#addresses.
func EscapeBusAddressValue(val string) string {
toEsc := strNeedsEscape(val)
if toEsc == 0 {
// Avoid unneeded allocation/copying.
return val
}
// Avoid allocation for short paths.
var buf [64]byte
var out []byte
// Every to-be-escaped byte needs 2 extra bytes.
required := len(val) + 2*toEsc
if required <= len(buf) {
out = buf[:required]
} else {
out = make([]byte, required)
}
j := 0
for i := 0; i < len(val); i++ {
if ch := val[i]; needsEscape(ch) {
// Convert ch to %xx, where xx is hex value.
out[j] = '%'
out[j+1] = hexchar(ch >> 4)
out[j+2] = hexchar(ch & 0x0F)
j += 3
} else {
out[j] = ch
j++
}
}
return string(out)
}
// UnescapeBusAddressValue unescapes values in D-Bus server addresses,
// as defined by the D-Bus specification at
// https://dbus.freedesktop.org/doc/dbus-specification.html#addresses.
func UnescapeBusAddressValue(val string) (string, error) {
// Looks like url.PathUnescape does exactly what is required.
return url.PathUnescape(val)
}
// hexchar returns an octal representation of a n, where n < 16.
// For invalid values of n, the function panics.
func hexchar(n byte) byte {
const hex = "0123456789abcdef"
// For n >= len(hex), runtime will panic.
return hex[n]
}
// needsEscape tells if a byte is NOT one of optionally-escaped bytes.
func needsEscape(c byte) bool {
if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' {
return false
}
switch c {
case '-', '_', '/', '\\', '.', '*':
return false
}
return true
}
// strNeedsEscape tells how many bytes in the string need escaping.
func strNeedsEscape(val string) int {
count := 0
for i := 0; i < len(val); i++ {
if needsEscape(val[i]) {
count++
}
}
return count
}

View File

@ -3,6 +3,7 @@ package dbus
import (
"errors"
"fmt"
"os"
"reflect"
"strings"
)
@ -26,6 +27,27 @@ var (
}
)
func MakeNoObjectError(path ObjectPath) Error {
return Error{
"org.freedesktop.DBus.Error.NoSuchObject",
[]interface{}{fmt.Sprintf("No such object '%s'", string(path))},
}
}
func MakeUnknownMethodError(methodName string) Error {
return Error{
"org.freedesktop.DBus.Error.UnknownMethod",
[]interface{}{fmt.Sprintf("Unknown / invalid method '%s'", methodName)},
}
}
func MakeUnknownInterfaceError(ifaceName string) Error {
return Error{
"org.freedesktop.DBus.Error.UnknownInterface",
[]interface{}{fmt.Sprintf("Object does not implement the interface '%s'", ifaceName)},
}
}
func MakeFailedError(err error) *Error {
return &Error{
"org.freedesktop.DBus.Error.Failed",
@ -69,6 +91,22 @@ func getMethods(in interface{}, mapping map[string]string) map[string]reflect.Va
return methods
}
func getAllMethods(in interface{}, mapping map[string]string) map[string]reflect.Value {
if in == nil {
return nil
}
methods := make(map[string]reflect.Value)
val := reflect.ValueOf(in)
typ := val.Type()
for i := 0; i < typ.NumMethod(); i++ {
methtype := typ.Method(i)
method := val.Method(i)
// map names while building table
methods[computeMethodName(methtype.Name, mapping)] = method
}
return methods
}
func standardMethodArgumentDecode(m Method, sender string, msg *Message, body []interface{}) ([]interface{}, error) {
pointers := make([]interface{}, m.NumArguments())
decode := make([]interface{}, 0, len(body))
@ -112,6 +150,11 @@ func (conn *Conn) handleCall(msg *Message) {
ifaceName, _ := msg.Headers[FieldInterface].value.(string)
sender, hasSender := msg.Headers[FieldSender].value.(string)
serial := msg.serial
if len(name) == 0 {
conn.sendError(ErrMsgUnknownMethod, sender, serial)
}
if ifaceName == "org.freedesktop.DBus.Peer" {
switch name {
case "Ping":
@ -119,29 +162,26 @@ func (conn *Conn) handleCall(msg *Message) {
case "GetMachineId":
conn.sendReply(sender, serial, conn.uuid)
default:
conn.sendError(ErrMsgUnknownMethod, sender, serial)
conn.sendError(MakeUnknownMethodError(name), sender, serial)
}
return
}
if len(name) == 0 {
conn.sendError(ErrMsgUnknownMethod, sender, serial)
}
object, ok := conn.handler.LookupObject(path)
if !ok {
conn.sendError(ErrMsgNoObject, sender, serial)
conn.sendError(MakeNoObjectError(path), sender, serial)
return
}
iface, exists := object.LookupInterface(ifaceName)
if !exists {
conn.sendError(ErrMsgUnknownInterface, sender, serial)
conn.sendError(MakeUnknownInterfaceError(ifaceName), sender, serial)
return
}
m, exists := iface.LookupMethod(name)
if !exists {
conn.sendError(ErrMsgUnknownMethod, sender, serial)
conn.sendError(MakeUnknownMethodError(name), sender, serial)
return
}
args, err := conn.decodeArguments(m, sender, msg)
@ -159,7 +199,6 @@ func (conn *Conn) handleCall(msg *Message) {
if msg.Flags&FlagNoReplyExpected == 0 {
reply := new(Message)
reply.Type = TypeMethodReply
reply.serial = conn.getSerial()
reply.Headers = make(map[HeaderField]Variant)
if hasSender {
reply.Headers[FieldDestination] = msg.Headers[FieldSender]
@ -171,31 +210,25 @@ func (conn *Conn) handleCall(msg *Message) {
}
reply.Headers[FieldSignature] = MakeVariant(SignatureOf(reply.Body...))
conn.sendMessageAndIfClosed(reply, nil)
if err := reply.IsValid(); err != nil {
fmt.Fprintf(os.Stderr, "dbus: dropping invalid reply to %s.%s on obj %s: %s\n", ifaceName, name, path, err)
} else {
conn.sendMessageAndIfClosed(reply, nil)
}
}
}
// Emit emits the given signal on the message bus. The name parameter must be
// formatted as "interface.member", e.g., "org.freedesktop.DBus.NameLost".
func (conn *Conn) Emit(path ObjectPath, name string, values ...interface{}) error {
if !path.IsValid() {
return errors.New("dbus: invalid object path")
}
i := strings.LastIndex(name, ".")
if i == -1 {
return errors.New("dbus: invalid method name")
}
iface := name[:i]
member := name[i+1:]
if !isValidMember(member) {
return errors.New("dbus: invalid method name")
}
if !isValidInterface(iface) {
return errors.New("dbus: invalid interface name")
}
msg := new(Message)
msg.Type = TypeSignal
msg.serial = conn.getSerial()
msg.Headers = make(map[HeaderField]Variant)
msg.Headers[FieldInterface] = MakeVariant(iface)
msg.Headers[FieldMember] = MakeVariant(member)
@ -204,6 +237,9 @@ func (conn *Conn) Emit(path ObjectPath, name string, values ...interface{}) erro
if len(values) > 0 {
msg.Headers[FieldSignature] = MakeVariant(SignatureOf(values...))
}
if err := msg.IsValid(); err != nil {
return err
}
var closed bool
conn.sendMessageAndIfClosed(msg, func() {
@ -247,6 +283,18 @@ func (conn *Conn) Export(v interface{}, path ObjectPath, iface string) error {
return conn.ExportWithMap(v, nil, path, iface)
}
// ExportAll registers all exported methods defined by the given object on
// the message bus.
//
// Unlike Export there is no requirement to have the last parameter as type
// *Error. If you want to be able to return error then you can append an error
// type parameter to your method signature. If the error returned is not nil,
// it is sent back to the caller as an error. Otherwise, a method reply is
// sent with the other return values as its body.
func (conn *Conn) ExportAll(v interface{}, path ObjectPath, iface string) error {
return conn.export(getAllMethods(v, nil), path, iface, false)
}
// ExportWithMap works exactly like Export but provides the ability to remap
// method names (e.g. export a lower-case method).
//
@ -299,19 +347,22 @@ func (conn *Conn) ExportSubtreeMethodTable(methods map[string]interface{}, path
}
func (conn *Conn) exportMethodTable(methods map[string]interface{}, path ObjectPath, iface string, includeSubtree bool) error {
out := make(map[string]reflect.Value)
for name, method := range methods {
rval := reflect.ValueOf(method)
if rval.Kind() != reflect.Func {
continue
var out map[string]reflect.Value
if methods != nil {
out = make(map[string]reflect.Value)
for name, method := range methods {
rval := reflect.ValueOf(method)
if rval.Kind() != reflect.Func {
continue
}
t := rval.Type()
// only track valid methods must return *Error as last arg
if t.NumOut() == 0 ||
t.Out(t.NumOut()-1) != reflect.TypeOf(&ErrMsgInvalidArg) {
continue
}
out[name] = rval
}
t := rval.Type()
// only track valid methods must return *Error as last arg
if t.NumOut() == 0 ||
t.Out(t.NumOut()-1) != reflect.TypeOf(&ErrMsgInvalidArg) {
continue
}
out[name] = rval
}
return conn.export(out, path, iface, includeSubtree)
}
@ -327,12 +378,12 @@ func (conn *Conn) unexport(h *defaultHandler, path ObjectPath, iface string) err
return nil
}
// exportWithMap is the worker function for all exports/registrations.
// export is the worker function for all exports/registrations.
func (conn *Conn) export(methods map[string]reflect.Value, path ObjectPath, iface string, includeSubtree bool) error {
h, ok := conn.handler.(*defaultHandler)
if !ok {
return fmt.Errorf(
`dbus: export only allowed on the default hander handler have %T"`,
`dbus: export only allowed on the default handler. Received: %T"`,
conn.handler)
}

View File

@ -2,27 +2,24 @@ package dbus
import (
"os"
"sync"
)
var (
homeDir string
homeDirLock sync.Mutex
"os/user"
)
// Get returns the home directory of the current user, which is usually the
// value of HOME environment variable. In case it is not set or empty, os/user
// package is used.
//
// If linking statically with cgo enabled against glibc, make sure the
// osusergo build tag is used.
//
// If needing to do nss lookups, do not disable cgo or set osusergo.
func getHomeDir() string {
homeDirLock.Lock()
defer homeDirLock.Unlock()
homeDir := os.Getenv("HOME")
if homeDir != "" {
return homeDir
}
homeDir = os.Getenv("HOME")
if homeDir != "" {
return homeDir
if u, err := user.Current(); err == nil {
return u.HomeDir
}
homeDir = lookupHomeDir()
return homeDir
return "/"
}

View File

@ -1,15 +0,0 @@
// +build !static_build
package dbus
import (
"os/user"
)
func lookupHomeDir() string {
u, err := user.Current()
if err != nil {
return "/"
}
return u.HomeDir
}

View File

@ -1,45 +0,0 @@
// +build static_build
package dbus
import (
"bufio"
"os"
"strconv"
"strings"
)
func lookupHomeDir() string {
myUid := os.Getuid()
f, err := os.Open("/etc/passwd")
if err != nil {
return "/"
}
defer f.Close()
s := bufio.NewScanner(f)
for s.Scan() {
if err := s.Err(); err != nil {
break
}
line := strings.TrimSpace(s.Text())
if line == "" {
continue
}
parts := strings.Split(line, ":")
if len(parts) >= 6 {
uid, err := strconv.Atoi(parts[2])
if err == nil && uid == myUid {
return parts[5]
}
}
}
// Default to / if we can't get a better value
return "/"
}

Some files were not shown because too many files have changed in this diff Show More