github.com/algorand/go-algorand-sdk@v1.24.0/crypto/account_test.go (about) 1 package crypto 2 3 import ( 4 "testing" 5 6 "github.com/stretchr/testify/require" 7 "golang.org/x/crypto/ed25519" 8 9 "github.com/algorand/go-algorand-sdk/mnemonic" 10 "github.com/algorand/go-algorand-sdk/types" 11 ) 12 13 func TestGenerateAccount(t *testing.T) { 14 kp := GenerateAccount() 15 16 // Public key should not be empty 17 require.NotEqual(t, ed25519.PublicKey{}, kp.PublicKey) 18 19 // Private key should not be empty 20 require.NotEqual(t, ed25519.PrivateKey{}, kp.PrivateKey) 21 22 // Account should equal itself 23 require.Equal(t, kp, kp) 24 25 // Address should be identical to public key 26 pk := ed25519.PublicKey(kp.Address[:]) 27 require.Equal(t, pk, kp.PublicKey) 28 29 message := []byte("test message") 30 sig := ed25519.Sign(kp.PrivateKey, message) 31 // Public key should verify signature from private key 32 require.True(t, ed25519.Verify(kp.PublicKey, message, sig)) 33 34 kp2 := GenerateAccount() 35 // Calling the function again should produce a different account 36 require.NotEqual(t, kp, kp2) 37 } 38 39 func TestAccountFromPrivateKey(t *testing.T) { 40 exampleAccount := Account{ 41 PrivateKey: ed25519.PrivateKey{0xd2, 0xdc, 0x4c, 0xcc, 0xe9, 0x98, 0x62, 0xff, 0xcf, 0x8c, 0xeb, 0x93, 0x6, 0xc4, 0x8d, 0xa6, 0x80, 0x50, 0x82, 0xa, 0xbb, 0x29, 0x95, 0x7a, 0xac, 0x82, 0x68, 0x9a, 0x8c, 0x49, 0x5a, 0x38, 0x5e, 0x67, 0x4f, 0x1c, 0xa, 0xee, 0xec, 0x37, 0x71, 0x89, 0x8f, 0x61, 0xc7, 0x6f, 0xf5, 0xd2, 0x4a, 0x19, 0x79, 0x3e, 0x2c, 0x91, 0xfa, 0x8, 0x51, 0x62, 0x63, 0xe3, 0x85, 0x73, 0xea, 0x42}, 42 PublicKey: ed25519.PublicKey{0x5e, 0x67, 0x4f, 0x1c, 0xa, 0xee, 0xec, 0x37, 0x71, 0x89, 0x8f, 0x61, 0xc7, 0x6f, 0xf5, 0xd2, 0x4a, 0x19, 0x79, 0x3e, 0x2c, 0x91, 0xfa, 0x8, 0x51, 0x62, 0x63, 0xe3, 0x85, 0x73, 0xea, 0x42}, 43 Address: types.Address{0x5e, 0x67, 0x4f, 0x1c, 0xa, 0xee, 0xec, 0x37, 0x71, 0x89, 0x8f, 0x61, 0xc7, 0x6f, 0xf5, 0xd2, 0x4a, 0x19, 0x79, 0x3e, 0x2c, 0x91, 0xfa, 0x8, 0x51, 0x62, 0x63, 0xe3, 0x85, 0x73, 0xea, 0x42}, 44 } 45 46 t.Run("From private key", func(t *testing.T) { 47 pk := exampleAccount.PrivateKey[:] 48 49 actual, err := AccountFromPrivateKey(pk) 50 require.NoError(t, err) 51 52 require.Equal(t, exampleAccount, actual) 53 }) 54 55 t.Run("From seed only", func(t *testing.T) { 56 pk := exampleAccount.PrivateKey.Seed() // get just the seed portion of the private key (first 32 bytes) 57 58 _, err := AccountFromPrivateKey(pk) 59 require.Error(t, err, errInvalidPrivateKey) 60 }) 61 62 t.Run("From mnemonic", func(t *testing.T) { 63 m := "olympic cricket tower model share zone grid twist sponsor avoid eight apology patient party success claim famous rapid donor pledge bomb mystery security ability often" 64 pk, err := mnemonic.ToPrivateKey(m) 65 require.NoError(t, err) 66 67 actual, err := AccountFromPrivateKey(pk) 68 require.NoError(t, err) 69 70 require.Equal(t, exampleAccount, actual) 71 }) 72 } 73 74 func TestMultisigAccount_Address(t *testing.T) { 75 addr1, err := types.DecodeAddress("XMHLMNAVJIMAW2RHJXLXKKK4G3J3U6VONNO3BTAQYVDC3MHTGDP3J5OCRU") 76 require.NoError(t, err) 77 addr2, err := types.DecodeAddress("HTNOX33OCQI2JCOLZ2IRM3BC2WZ6JUILSLEORBPFI6W7GU5Q4ZW6LINHLA") 78 require.NoError(t, err) 79 addr3, err := types.DecodeAddress("E6JSNTY4PVCY3IRZ6XEDHEO6VIHCQ5KGXCIQKFQCMB2N6HXRY4IB43VSHI") 80 require.NoError(t, err) 81 ma, err := MultisigAccountWithParams(1, 2, []types.Address{ 82 addr1, 83 addr2, 84 addr3, 85 }) 86 require.NoError(t, err) 87 addrMultisig, err := ma.Address() 88 require.NoError(t, err) 89 require.Equal(t, 90 "UCE2U2JC4O4ZR6W763GUQCG57HQCDZEUJY4J5I6VYY4HQZUJDF7AKZO5GM", 91 addrMultisig.String(), 92 ) 93 } 94 95 func TestMultisigAccount_ZeroThreshInvalid(t *testing.T) { 96 addr1, err := types.DecodeAddress("XMHLMNAVJIMAW2RHJXLXKKK4G3J3U6VONNO3BTAQYVDC3MHTGDP3J5OCRU") 97 require.NoError(t, err) 98 ma, err := MultisigAccountWithParams(1, 0, []types.Address{ 99 addr1, 100 }) 101 require.Error(t, ma.Validate()) 102 } 103 104 func TestMultisigAccount_Version1Only(t *testing.T) { 105 addr1, err := types.DecodeAddress("XMHLMNAVJIMAW2RHJXLXKKK4G3J3U6VONNO3BTAQYVDC3MHTGDP3J5OCRU") 106 require.NoError(t, err) 107 ma, err := MultisigAccountWithParams(0, 1, []types.Address{ 108 addr1, 109 }) 110 require.Error(t, ma.Validate()) 111 112 ma, err = MultisigAccountWithParams(2, 1, []types.Address{ 113 addr1, 114 }) 115 require.Error(t, ma.Validate()) 116 } 117 118 func TestLogicSigAddress(t *testing.T) { 119 program := []byte{1, 32, 1, 1, 34} 120 var args [][]byte 121 122 expectedAddr, err := types.DecodeAddress("6Z3C3LDVWGMX23BMSYMANACQOSINPFIRF77H7N3AWJZYV6OH6GWTJKVMXY") 123 require.NoError(t, err) 124 125 t.Run("no sig", func(t *testing.T) { 126 var sk ed25519.PrivateKey 127 var ma MultisigAccount 128 129 lsig, err := MakeLogicSig(program, args, sk, ma) 130 require.NoError(t, err) 131 132 actualAddr := LogicSigAddress(lsig) 133 require.Equal(t, expectedAddr, actualAddr) 134 }) 135 136 t.Run("single sig", func(t *testing.T) { 137 account, err := AccountFromPrivateKey(ed25519.PrivateKey{0xd2, 0xdc, 0x4c, 0xcc, 0xe9, 0x98, 0x62, 0xff, 0xcf, 0x8c, 0xeb, 0x93, 0x6, 0xc4, 0x8d, 0xa6, 0x80, 0x50, 0x82, 0xa, 0xbb, 0x29, 0x95, 0x7a, 0xac, 0x82, 0x68, 0x9a, 0x8c, 0x49, 0x5a, 0x38, 0x5e, 0x67, 0x4f, 0x1c, 0xa, 0xee, 0xec, 0x37, 0x71, 0x89, 0x8f, 0x61, 0xc7, 0x6f, 0xf5, 0xd2, 0x4a, 0x19, 0x79, 0x3e, 0x2c, 0x91, 0xfa, 0x8, 0x51, 0x62, 0x63, 0xe3, 0x85, 0x73, 0xea, 0x42}) 138 require.NoError(t, err) 139 140 var ma MultisigAccount 141 142 lsig, err := MakeLogicSig(program, args, account.PrivateKey, ma) 143 require.NoError(t, err) 144 145 // for backwards compatibility, we still expect the hashed program bytes address 146 actualAddr := LogicSigAddress(lsig) 147 require.Equal(t, expectedAddr, actualAddr) 148 }) 149 150 t.Run("multi sig", func(t *testing.T) { 151 ma, sk1, _, _ := makeTestMultisigAccount(t) 152 153 lsig, err := MakeLogicSig(program, args, sk1, ma) 154 require.NoError(t, err) 155 156 // for backwards compatibility, we still expect the hashed program bytes address 157 actualAddr := LogicSigAddress(lsig) 158 require.Equal(t, expectedAddr, actualAddr) 159 }) 160 } 161 162 func TestMakeLogicSigAccount(t *testing.T) { 163 program := []byte{1, 32, 1, 1, 34} 164 args := [][]byte{ 165 {0x01}, 166 {0x02, 0x03}, 167 } 168 169 t.Run("Escrow", func(t *testing.T) { 170 lsigAccount := MakeLogicSigAccountEscrow(program, args) 171 172 require.Equal(t, program, lsigAccount.Lsig.Logic) 173 require.Equal(t, args, lsigAccount.Lsig.Args) 174 require.Equal(t, types.Signature{}, lsigAccount.Lsig.Sig) 175 require.True(t, lsigAccount.Lsig.Msig.Blank()) 176 require.Equal(t, ed25519.PublicKey(nil), lsigAccount.SigningKey) 177 178 require.False(t, lsigAccount.IsDelegated()) 179 }) 180 181 t.Run("Delegated", func(t *testing.T) { 182 account, err := AccountFromPrivateKey(ed25519.PrivateKey{0xd2, 0xdc, 0x4c, 0xcc, 0xe9, 0x98, 0x62, 0xff, 0xcf, 0x8c, 0xeb, 0x93, 0x6, 0xc4, 0x8d, 0xa6, 0x80, 0x50, 0x82, 0xa, 0xbb, 0x29, 0x95, 0x7a, 0xac, 0x82, 0x68, 0x9a, 0x8c, 0x49, 0x5a, 0x38, 0x5e, 0x67, 0x4f, 0x1c, 0xa, 0xee, 0xec, 0x37, 0x71, 0x89, 0x8f, 0x61, 0xc7, 0x6f, 0xf5, 0xd2, 0x4a, 0x19, 0x79, 0x3e, 0x2c, 0x91, 0xfa, 0x8, 0x51, 0x62, 0x63, 0xe3, 0x85, 0x73, 0xea, 0x42}) 183 require.NoError(t, err) 184 185 lsigAccount, err := MakeLogicSigAccountDelegated(program, args, account.PrivateKey) 186 require.NoError(t, err) 187 188 expectedSignature := types.Signature{0x3e, 0x5, 0x3d, 0x39, 0x4d, 0xfb, 0x12, 0xbc, 0x65, 0x79, 0x9f, 0xea, 0x31, 0x8a, 0x7b, 0x8e, 0xa2, 0x51, 0x8b, 0x55, 0x2c, 0x8a, 0xbe, 0x6c, 0xd7, 0xa7, 0x65, 0x2d, 0xd8, 0xb0, 0x18, 0x7e, 0x21, 0x5, 0x2d, 0xb9, 0x24, 0x62, 0x89, 0x16, 0xe5, 0x61, 0x74, 0xcd, 0xf, 0x19, 0xac, 0xb9, 0x6c, 0x45, 0xa4, 0x29, 0x91, 0x99, 0x11, 0x1d, 0xe4, 0x7c, 0xe4, 0xfc, 0x12, 0xec, 0xce, 0x2} 189 190 require.Equal(t, program, lsigAccount.Lsig.Logic) 191 require.Equal(t, args, lsigAccount.Lsig.Args) 192 require.Equal(t, expectedSignature, lsigAccount.Lsig.Sig) 193 require.True(t, lsigAccount.Lsig.Msig.Blank()) 194 require.Equal(t, account.PublicKey, lsigAccount.SigningKey) 195 196 require.True(t, lsigAccount.IsDelegated()) 197 }) 198 199 t.Run("DelegatedMsig", func(t *testing.T) { 200 ma, sk1, sk2, _ := makeTestMultisigAccount(t) 201 202 lsigAccount, err := MakeLogicSigAccountDelegatedMsig(program, args, ma, sk1) 203 require.NoError(t, err) 204 205 expectedMsig := types.MultisigSig{ 206 Version: ma.Version, 207 Threshold: ma.Threshold, 208 Subsigs: []types.MultisigSubsig{ 209 { 210 Key: ma.Pks[0], 211 Sig: types.Signature{0x49, 0x13, 0xb8, 0x5, 0xd1, 0x9e, 0x7f, 0x2c, 0x10, 0x80, 0xf6, 0x33, 0x7e, 0x18, 0x54, 0xa7, 0xce, 0xea, 0xee, 0x10, 0xdd, 0xbd, 0x13, 0x65, 0x84, 0xbf, 0x93, 0xb7, 0x5f, 0x30, 0x63, 0x15, 0x91, 0xca, 0x23, 0xc, 0xed, 0xef, 0x23, 0xd1, 0x74, 0x1b, 0x52, 0x9d, 0xb0, 0xff, 0xef, 0x37, 0x54, 0xd6, 0x46, 0xf4, 0xb5, 0x61, 0xfc, 0x8b, 0xbc, 0x2d, 0x7b, 0x4e, 0x63, 0x5c, 0xbd, 0x2}, 212 }, 213 { 214 Key: ma.Pks[1], 215 }, 216 { 217 Key: ma.Pks[2], 218 }, 219 }, 220 } 221 222 require.Equal(t, program, lsigAccount.Lsig.Logic) 223 require.Equal(t, args, lsigAccount.Lsig.Args) 224 require.Equal(t, types.Signature{}, lsigAccount.Lsig.Sig) 225 require.Equal(t, expectedMsig, lsigAccount.Lsig.Msig) 226 require.Equal(t, ed25519.PublicKey(nil), lsigAccount.SigningKey) 227 228 require.True(t, lsigAccount.IsDelegated()) 229 230 t.Run("AppendMultisigSignature", func(t *testing.T) { 231 err := lsigAccount.AppendMultisigSignature(sk2) 232 require.NoError(t, err) 233 234 expectedMsig.Subsigs[1].Sig = types.Signature{0x64, 0xbc, 0x55, 0xdb, 0xed, 0x91, 0xa2, 0x41, 0xd4, 0x2a, 0xb6, 0x60, 0xf7, 0xe1, 0x4a, 0xb9, 0x99, 0x9a, 0x52, 0xb3, 0xb1, 0x71, 0x58, 0xce, 0xfc, 0x3f, 0x4f, 0xe7, 0xcb, 0x22, 0x41, 0x14, 0xad, 0xa9, 0x3d, 0x5e, 0x84, 0x5, 0x2, 0xa, 0x17, 0xa6, 0x69, 0x83, 0x3, 0x22, 0x4e, 0x86, 0xa3, 0x8b, 0x6a, 0x36, 0xc5, 0x54, 0xbe, 0x20, 0x50, 0xff, 0xd3, 0xee, 0xa8, 0xb3, 0x4, 0x9} 235 236 require.Equal(t, program, lsigAccount.Lsig.Logic) 237 require.Equal(t, args, lsigAccount.Lsig.Args) 238 require.Equal(t, types.Signature{}, lsigAccount.Lsig.Sig) 239 require.Equal(t, expectedMsig, lsigAccount.Lsig.Msig) 240 require.Equal(t, ed25519.PublicKey(nil), lsigAccount.SigningKey) 241 242 require.True(t, lsigAccount.IsDelegated()) 243 }) 244 }) 245 } 246 247 func TestLogicSigAccountFromLogicSig(t *testing.T) { 248 program := []byte{1, 32, 1, 1, 34} 249 args := [][]byte{ 250 {0x01}, 251 {0x02, 0x03}, 252 } 253 254 programAddr, err := types.DecodeAddress("6Z3C3LDVWGMX23BMSYMANACQOSINPFIRF77H7N3AWJZYV6OH6GWTJKVMXY") 255 require.NoError(t, err) 256 257 programPublicKey := make(ed25519.PublicKey, len(programAddr)) 258 copy(programPublicKey, programAddr[:]) 259 260 t.Run("no sig", func(t *testing.T) { 261 var sk ed25519.PrivateKey 262 var ma MultisigAccount 263 264 lsig, err := MakeLogicSig(program, args, sk, ma) 265 require.NoError(t, err) 266 267 t.Run("with public key", func(t *testing.T) { 268 _, err := LogicSigAccountFromLogicSig(lsig, &programPublicKey) 269 require.Error(t, err, errLsigAccountPublicKeyNotNeeded) 270 }) 271 272 t.Run("without public key", func(t *testing.T) { 273 lsigAccount, err := LogicSigAccountFromLogicSig(lsig, nil) 274 require.NoError(t, err) 275 276 require.Equal(t, lsig, lsigAccount.Lsig) 277 require.Equal(t, ed25519.PublicKey(nil), lsigAccount.SigningKey) 278 279 require.False(t, lsigAccount.IsDelegated()) 280 }) 281 }) 282 283 t.Run("single sig", func(t *testing.T) { 284 account, err := AccountFromPrivateKey(ed25519.PrivateKey{0xd2, 0xdc, 0x4c, 0xcc, 0xe9, 0x98, 0x62, 0xff, 0xcf, 0x8c, 0xeb, 0x93, 0x6, 0xc4, 0x8d, 0xa6, 0x80, 0x50, 0x82, 0xa, 0xbb, 0x29, 0x95, 0x7a, 0xac, 0x82, 0x68, 0x9a, 0x8c, 0x49, 0x5a, 0x38, 0x5e, 0x67, 0x4f, 0x1c, 0xa, 0xee, 0xec, 0x37, 0x71, 0x89, 0x8f, 0x61, 0xc7, 0x6f, 0xf5, 0xd2, 0x4a, 0x19, 0x79, 0x3e, 0x2c, 0x91, 0xfa, 0x8, 0x51, 0x62, 0x63, 0xe3, 0x85, 0x73, 0xea, 0x42}) 285 require.NoError(t, err) 286 287 var ma MultisigAccount 288 289 lsig, err := MakeLogicSig(program, args, account.PrivateKey, ma) 290 require.NoError(t, err) 291 292 t.Run("with correct public key", func(t *testing.T) { 293 lsigAccount, err := LogicSigAccountFromLogicSig(lsig, &account.PublicKey) 294 require.NoError(t, err) 295 296 require.Equal(t, lsig, lsigAccount.Lsig) 297 require.Equal(t, account.PublicKey, lsigAccount.SigningKey) 298 299 require.True(t, lsigAccount.IsDelegated()) 300 }) 301 302 t.Run("with incorrect public key", func(t *testing.T) { 303 var wrongPublicKey = make(ed25519.PublicKey, len(account.PublicKey)) 304 copy(wrongPublicKey, account.PublicKey) 305 wrongPublicKey[0] = 0xff 306 _, err := LogicSigAccountFromLogicSig(lsig, &wrongPublicKey) 307 require.Error(t, err, errLsigInvalidPublicKey) 308 }) 309 310 t.Run("without public key", func(t *testing.T) { 311 _, err := LogicSigAccountFromLogicSig(lsig, nil) 312 require.Error(t, err, errLsigNoPublicKey) 313 }) 314 }) 315 316 t.Run("multi sig", func(t *testing.T) { 317 ma, sk1, _, _ := makeTestMultisigAccount(t) 318 319 lsig, err := MakeLogicSig(program, args, sk1, ma) 320 require.NoError(t, err) 321 322 t.Run("with public key", func(t *testing.T) { 323 msigAddr, err := ma.Address() 324 require.NoError(t, err) 325 326 msigPublicKey := make(ed25519.PublicKey, len(msigAddr)) 327 copy(msigPublicKey, msigAddr[:]) 328 329 _, err = LogicSigAccountFromLogicSig(lsig, &msigPublicKey) 330 require.Error(t, err, errLsigAccountPublicKeyNotNeeded) 331 }) 332 333 t.Run("without public key", func(t *testing.T) { 334 lsigAccount, err := LogicSigAccountFromLogicSig(lsig, nil) 335 require.NoError(t, err) 336 337 require.Equal(t, lsig, lsigAccount.Lsig) 338 require.Equal(t, ed25519.PublicKey(nil), lsigAccount.SigningKey) 339 340 require.True(t, lsigAccount.IsDelegated()) 341 }) 342 }) 343 } 344 345 func TestLogicSigAccount_Address(t *testing.T) { 346 program := []byte{1, 32, 1, 1, 34} 347 args := [][]byte{ 348 {0x01}, 349 {0x02, 0x03}, 350 } 351 352 t.Run("no sig", func(t *testing.T) { 353 lsigAccount := MakeLogicSigAccountEscrow(program, args) 354 355 expectedAddr, err := types.DecodeAddress("6Z3C3LDVWGMX23BMSYMANACQOSINPFIRF77H7N3AWJZYV6OH6GWTJKVMXY") 356 require.NoError(t, err) 357 358 actualAddr, err := lsigAccount.Address() 359 require.NoError(t, err) 360 require.Equal(t, expectedAddr, actualAddr) 361 }) 362 363 t.Run("single sig", func(t *testing.T) { 364 account, err := AccountFromPrivateKey(ed25519.PrivateKey{0xd2, 0xdc, 0x4c, 0xcc, 0xe9, 0x98, 0x62, 0xff, 0xcf, 0x8c, 0xeb, 0x93, 0x6, 0xc4, 0x8d, 0xa6, 0x80, 0x50, 0x82, 0xa, 0xbb, 0x29, 0x95, 0x7a, 0xac, 0x82, 0x68, 0x9a, 0x8c, 0x49, 0x5a, 0x38, 0x5e, 0x67, 0x4f, 0x1c, 0xa, 0xee, 0xec, 0x37, 0x71, 0x89, 0x8f, 0x61, 0xc7, 0x6f, 0xf5, 0xd2, 0x4a, 0x19, 0x79, 0x3e, 0x2c, 0x91, 0xfa, 0x8, 0x51, 0x62, 0x63, 0xe3, 0x85, 0x73, 0xea, 0x42}) 365 require.NoError(t, err) 366 367 lsigAccount, err := MakeLogicSigAccountDelegated(program, args, account.PrivateKey) 368 require.NoError(t, err) 369 370 actualAddr, err := lsigAccount.Address() 371 require.NoError(t, err) 372 require.Equal(t, account.Address, actualAddr) 373 }) 374 375 t.Run("multi sig", func(t *testing.T) { 376 ma, sk1, _, _ := makeTestMultisigAccount(t) 377 maAddr, err := ma.Address() 378 require.NoError(t, err) 379 380 lsigAccount, err := MakeLogicSigAccountDelegatedMsig(program, args, ma, sk1) 381 require.NoError(t, err) 382 383 actualAddr, err := lsigAccount.Address() 384 require.NoError(t, err) 385 require.Equal(t, maAddr, actualAddr) 386 }) 387 }