From 0e73fd23c17468c3a24bb6f45898217adfec52ce Mon Sep 17 00:00:00 2001 From: pm-duokey Date: Fri, 17 Dec 2021 03:01:38 -0800 Subject: [PATCH 01/10] new Darc ECDSA --- calypso/protocol/ocs_test.go | 2 +- darc/darc.go | 61 ++++++++++++++++++++++++++++++++++++ darc/darc_test.go | 16 +++++++--- darc/proto.go | 17 ++++++++++ 4 files changed, 90 insertions(+), 6 deletions(-) diff --git a/calypso/protocol/ocs_test.go b/calypso/protocol/ocs_test.go index aab85e8803..24a83063fe 100644 --- a/calypso/protocol/ocs_test.go +++ b/calypso/protocol/ocs_test.go @@ -252,7 +252,7 @@ func DecodeKey(suite kyber.Group, X kyber.Point, Cs []kyber.Point, XhatEnc kyber } key = append(key, keyPart...) } - return + return } // starts a new service. No function needed. diff --git a/darc/darc.go b/darc/darc.go index 3a8506a79a..9ed13e286a 100644 --- a/darc/darc.go +++ b/darc/darc.go @@ -33,6 +33,7 @@ package darc import ( "bytes" "crypto/ecdsa" + "crypto/elliptic" "crypto/sha256" "crypto/sha512" "crypto/x509" @@ -773,6 +774,8 @@ func (s Signer) Type() int { return 3 case s.EvmContract != nil: return 4 + case s.ECDSA != nil: + return 5 default: return -1 } @@ -790,6 +793,8 @@ func (s Signer) Identity() Identity { return NewIdentityProxy(s.Proxy) case 4: return NewIdentityEvmContract(s.EvmContract) + case 5: + return NewIdentityECDSA(s.ECDSA.PublicKey) default: return Identity{} } @@ -937,6 +942,8 @@ func (id Identity) Verify(msg, sig []byte) error { return id.Proxy.Verify(msg, sig) case 4: return id.EvmContract.Verify(msg, sig) + case 5: + return id.ECDSA.Verify(msg, sig) default: return errors.New("unknown identity") } @@ -964,6 +971,10 @@ func (id Identity) GetPublicBytes() []byte { return buf case 4: return id.EvmContract.Address[:] + case 5: + buf := elliptic.Marshal(id.ECDSA.PublicKey.Curve, id.ECDSA.PublicKey.X, id.ECDSA.PublicKey.Y) + //TODO: add error check here? + return buf default: return nil } @@ -1012,6 +1023,25 @@ func NewIdentityX509EC(public []byte) Identity { } } +// NewIdentityECDSA creates a new ECDSA identity struct given a public key +func NewIdentityECDSA(publicKey ecdsa.PublicKey) Identity { + return Identity{ + ECDSA: &IdentityECDSA{ + PublicKey: publicKey, + }, + } +} + +//TODO make calls to tsm available +func (ide IdentityECDSA) Verify(msg []byte, sig []byte) error { + hashMsg := sha256.Sum256(msg) + valid := ecdsa.VerifyASN1(&ide.PublicKey, hashMsg[:], sig) + if !valid { + return errors.New("Signature failed to verify") + } + return nil +} + // NewIdentityProxy creates a new OpenID Connect identity struct. func NewIdentityProxy(s *SignerProxy) Identity { return Identity{ @@ -1120,6 +1150,8 @@ func ParseIdentity(in string) (Identity, error) { return parseIDProxy(fields[1]) case "evm_contract": return parseIDEvmContract(fields[1]) + case "secp256k1": + return parseIDECDSA(fields[1]) default: return Identity{}, fmt.Errorf("unknown identity type %v", fields[0]) } @@ -1142,6 +1174,25 @@ func parseIDX509ec(in string) (Identity, error) { return Identity{X509EC: &IdentityX509EC{Public: id}}, nil } +//necessary function, needs to be refactored only supports elliptic.P256 curve +//needs to be tested Unmarshal might not work +func parseIDECDSA(in string) (Identity, error) { + id := make([]byte, hex.DecodedLen(len(in))) + _, err := hex.Decode(id, []byte(in)) + + x, y := elliptic.Unmarshal(elliptic.P256(), id) + + pubkey := ecdsa.PublicKey{ + Curve: elliptic.P256(), + X: x, + Y: y, + } + if err != nil { + return Identity{}, err + } + return Identity{ECDSA: &IdentityECDSA{PublicKey: pubkey}}, nil +} + func parseIDDarc(in string) (Identity, error) { id := make([]byte, hex.DecodedLen(len(in))) _, err := hex.Decode(id, []byte(in)) @@ -1447,6 +1498,16 @@ func (kcs SignerX509EC) Sign(msg []byte) ([]byte, error) { return nil, errors.New("not yet implemented") } +func NewSignerECDSA() Signer { + return Signer{} +} + +//TODO +func (kcs SignerECDSA) Sign(msg []byte) ([]byte, error) { + //call tsm to sign + return nil, errors.New("not yet implemented") +} + // NewSignerProxy creates a new SignerProxy. When Sign is called, the getSignature // callback will be called, so that the caller can use the appropriate mechanism // to retrieve and/or construct the signature. diff --git a/darc/darc_test.go b/darc/darc_test.go index 9f0cf289db..59a91c9f88 100644 --- a/darc/darc_test.go +++ b/darc/darc_test.go @@ -1,6 +1,7 @@ package darc import ( + "encoding/hex" "errors" "fmt" "net/url" @@ -751,11 +752,16 @@ func TestParseIdentity(t *testing.T) { // Test any identity func testIdentity(t *testing.T, sig Signer) { - msg := []byte("something secret") - signed, err := sig.Sign(msg) - require.NoError(t, err) - - id := sig.Identity() + msg := []byte(`Hello World`) + //signed, err := sig.Sign(msg) + //require.NoError(t, err) + + //Public Key: 0ab07149ce744429b7755e6a3d4c277d2f7a2a61ad93cfd18d6aa652e92069db + //Signature: 9626e46f0be4b96c65742e2a81945536fff6a23fad1a40b9cb0b6030cebaac293b6caf7cdc569e689a92db81176f380f6045cc72cd013f9cd4a1cb5bfa077d00 + signed, _ := hex.DecodeString("9626e46f0be4b96c65742e2a81945536fff6a23fad1a40b9cb0b6030cebaac293b6caf7cdc569e689a92db81176f380f6045cc72cd013f9cd4a1cb5bfa077d00") + in := "ed25519:0ab07149ce744429b7755e6a3d4c277d2f7a2a61ad93cfd18d6aa652e92069db" + id, _ := ParseIdentity(in) + //id := sig.Identity() require.NoError(t, id.Verify(msg, signed)) require.Error(t, id.Verify([]byte("wrong message"), signed)) } diff --git a/darc/proto.go b/darc/proto.go index 2367065a22..46fbb02ada 100644 --- a/darc/proto.go +++ b/darc/proto.go @@ -1,6 +1,8 @@ package darc import ( + "crypto/ecdsa" + "go.dedis.ch/cothority/v3/darc/expression" "go.dedis.ch/kyber/v3" "go.dedis.ch/onet/v3/network" @@ -71,6 +73,8 @@ type Identity struct { EvmContract *IdentityEvmContract // A claim signed by one of the keys in a DID Doc DID *IdentityDID + // Publik-key identity from an ECDSA key + ECDSA *IdentityECDSA } // IdentityEd25519 holds a Ed25519 public key (Point) @@ -78,6 +82,11 @@ type IdentityEd25519 struct { Point kyber.Point } +// IdentityECDSA holds a secp256k1 key (array of bytes) +type IdentityECDSA struct { + PublicKey ecdsa.PublicKey +} + // IdentityX509EC holds a public key from a X509EC type IdentityX509EC struct { Public []byte @@ -159,6 +168,7 @@ type Signer struct { Proxy *SignerProxy EvmContract *SignerEvmContract DID *SignerDID + ECDSA *SignerECDSA } // SignerEd25519 holds a public and private keys necessary to sign Darcs @@ -174,6 +184,13 @@ type SignerX509EC struct { secret []byte } +// SignerECDSA holds a public and private keys necessary to sign Darcs, +// but the private key will not be given out. +type SignerECDSA struct { + PublicKey ecdsa.PublicKey + PrivateKey ecdsa.PrivateKey +} + // SignerProxy holds the information necessary to verify claims // coming from external authentication systems via Authentication Proxies. type SignerProxy struct { From 596a5c730fcb3f46ab01ff938fcc161c08395067 Mon Sep 17 00:00:00 2001 From: pm-duokey Date: Mon, 20 Dec 2021 05:24:46 -0800 Subject: [PATCH 02/10] "implementation ECDSADarc" --- calypso/api_test.go | 124 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/calypso/api_test.go b/calypso/api_test.go index a57a56bd67..1b0be422b7 100644 --- a/calypso/api_test.go +++ b/calypso/api_test.go @@ -6,6 +6,7 @@ import ( "time" "go.dedis.ch/kyber/v3/sign/schnorr" + "go.dedis.ch/kyber/v3/util/key" "github.com/stretchr/testify/require" "go.dedis.ch/cothority/v3" @@ -217,3 +218,126 @@ func TestClient_Calypso(t *testing.T) { // use keyCopy to unlock the stuff in writeInstance.Data } + +// Tests the Calypso system with a simple write/read scenario. +// But it does the signing outside of the `Read` and `Write` methods for +// integration of the MPC signing by OneKey. +func TestClient_Calypso_Simple(t *testing.T) { + l := onet.NewTCPTest(cothority.Suite) + _, roster, _ := l.GenTree(3, true) + defer l.CloseAll() + + admin := darc.NewSignerEd25519(nil, nil) + adminCt := uint64(1) + user := darc.NewSignerEd25519(nil, nil) + // Initialise the genesis message and send it to the service. + // The admin has the privilege to spawn darcs + msg, err := byzcoin.DefaultGenesisMsg(byzcoin.CurrentVersion, roster, + []string{"spawn:" + ContractLongTermSecretID}, + admin.Identity()) + + msg.BlockInterval = 500 * time.Millisecond + require.NoError(t, err) + // The darc inside it should be valid. + gDarc := msg.GenesisDarc + require.Nil(t, gDarc.Verify(true)) + //Create Ledger + c, _, err := byzcoin.NewLedger(msg, false) + require.NoError(t, err) + //Create a Calypso Client (Byzcoin + Onet) + calypsoClient := NewClient(c) + + //Create the LTS sets up an aggregate public key used by the secret management committee + for _, who := range roster.List { + err := calypsoClient.Authorize(who, c.ID) + require.NoError(t, err) + } + ltsReply, err := calypsoClient.CreateLTS(roster, gDarc.GetBaseID(), []darc.Signer{admin}, []uint64{adminCt}) + adminCt++ + require.NoError(t, err) + //If no error, assign it + calypsoClient.ltsReply = ltsReply + + //Create a signer darc + userDarc := darc.NewDarc(darc.InitRules([]darc.Identity{user.Identity()}, + []darc.Identity{user.Identity()}), []byte("Provider1")) + // user can read and write. + // This can be changed to two different public keys. + err = userDarc.Rules.AddRule(darc.Action("spawn:"+ContractWriteID), + expression.InitOrExpr(user.Identity().String())) + require.NoError(t, err) + err = userDarc.Rules.AddRule(darc.Action("spawn:"+ContractReadID), + expression.InitOrExpr(user.Identity().String())) + require.NoError(t, err) + require.NotNil(t, userDarc) + _, err = calypsoClient.SpawnDarc(admin, adminCt, gDarc, *userDarc, 10) + adminCt++ + require.NoError(t, err) + + data := []byte("Some secret data - or the user's private key") + // Create a Write structure + write1, err := NewWriteData(cothority.Suite, + calypsoClient.ltsReply.InstanceID, + userDarc.GetBaseID(), calypsoClient.ltsReply.X, data) + require.NoError(t, err) + + // Create a write-instance and send it to Byzcoin - here + // the instruction and the transaction is created manually, + // so that an external signer can sign the hash of the instruction. + wrInst, err := ContractWriteSpawnInstruction(write1, userDarc) + require.NoError(t, err) + wrInst.SignerCounter = []uint64{1} + wrInst.SignerIdentities = []darc.Identity{user.Identity()} + wrTx, err := calypsoClient.bcClient.CreateTransaction(*wrInst) + require.NoError(t, err) + digest := wrTx.Instructions.Hash() + + // This signature can be replaced by an external signature. + signature, err := user.Sign(digest) + require.NoError(t, err) + wrTx.Instructions[0].Signatures = [][]byte{signature} + + // Send the transaction to ByzCoin + _, err = calypsoClient.bcClient.AddTransactionAndWait(wrTx, 10) + require.NoError(t, err) + wrID := wrTx.Instructions[0].DeriveID("") + proofWr, err := calypsoClient.WaitProof(wrID, time.Second, nil) + require.NoError(t, err) + + // Create a read-instance and send it to ByzCoin. + ephemeral := key.NewKeyPair(cothority.Suite) + readInst, err := ContractReadSpawnInstruction(wrID, ephemeral.Public) + require.NoError(t, err) + readInst.SignerCounter = []uint64{2} + readInst.SignerIdentities = []darc.Identity{user.Identity()} + readTx, err := calypsoClient.bcClient.CreateTransaction(*readInst) + require.NoError(t, err) + digest = readTx.Instructions.Hash() + + // This signature can be replaced by an external signature + signature, err = user.Sign(digest) + require.NoError(t, err) + readTx.Instructions[0].Signatures = [][]byte{signature} + readID := readTx.Instructions[0].DeriveID("") + + // Send the transaction to ByzCoin + _, err = calypsoClient.bcClient.AddTransactionAndWait(readTx, 10) + require.NoError(t, err) + proofRd, err := calypsoClient.WaitProof(readID, time.Second, + nil) + require.NoError(t, err) + + // Make sure you can actually decrypt + dk, err := calypsoClient.DecryptKey(&DecryptKey{Read: *proofRd, + Write: *proofWr}) + require.NoError(t, err) + require.True(t, dk.X.Equal(calypsoClient.ltsReply.X)) + keyCopy, err := dk.RecoverKey(ephemeral.Private) + require.NoError(t, err) + var wrCopy Write + require.NoError(t, proofWr.VerifyAndDecode(cothority.Suite, ContractWriteID, + &wrCopy)) + dataDecrypt, err := wrCopy.Decrypt(keyCopy) + require.NoError(t, err) + require.Equal(t, data, dataDecrypt) +} From 5c21329869cf345abae642679cfa87ca6a3472e2 Mon Sep 17 00:00:00 2001 From: pm-duokey Date: Mon, 20 Dec 2021 05:25:36 -0800 Subject: [PATCH 03/10] ECDSADarc --- calypso/contracts.go | 46 +++++++++++++++++++++++++++ calypso/struct.go | 75 ++++++++++++++++++++++++++++++++++++++++++++ darc/darc.go | 2 ++ darc/darc_test.go | 28 ++++++++++------- 4 files changed, 140 insertions(+), 11 deletions(-) diff --git a/calypso/contracts.go b/calypso/contracts.go index ef5ba8df2b..15af2a21b6 100644 --- a/calypso/contracts.go +++ b/calypso/contracts.go @@ -7,6 +7,7 @@ import ( "go.dedis.ch/cothority/v3" "go.dedis.ch/cothority/v3/byzcoin" "go.dedis.ch/cothority/v3/darc" + "go.dedis.ch/kyber/v3" "go.dedis.ch/onet/v3" "go.dedis.ch/onet/v3/log" "go.dedis.ch/onet/v3/network" @@ -278,3 +279,48 @@ func (c ContractWrite) VerifyInstruction(rst byzcoin.ReadOnlyStateTrie, inst byz } return inst.VerifyWithOption(rst, ctxHash, nil) } + +// ContractWriteSpawnInstruction returns the spawn instruction for a Write +// contract. +func ContractWriteSpawnInstruction(wr *Write, + d *darc.Darc) (*byzcoin.Instruction, error) { + writeBuf, err := protobuf.Encode(wr) + if err != nil { + return nil, xerrors.Errorf("couldn't encode write: %v", err) + } + return &byzcoin.Instruction{ + InstanceID: byzcoin.NewInstanceID(d.GetBaseID()), + Spawn: &byzcoin.Spawn{ + ContractID: ContractWriteID, + Args: byzcoin.Arguments{ + { + Name: "write", + Value: writeBuf, + }, + }, + }, + }, nil +} + +// ContractReadSpawnInstruction returns the spawn instruction for a Read +// contract. +func ContractReadSpawnInstruction(wrID byzcoin.InstanceID, + xc kyber.Point) (*byzcoin.Instruction, error) { + var readBuf []byte + read := &Read{ + Write: wrID, + Xc: xc, + } + readBuf, err := protobuf.Encode(read) + if err != nil { + return nil, xerrors.Errorf("encoding Read message: %v", err) + } + + return &byzcoin.Instruction{ + InstanceID: wrID, + Spawn: &byzcoin.Spawn{ + ContractID: ContractReadID, + Args: byzcoin.Arguments{{Name: "read", Value: readBuf}}, + }, + }, nil +} diff --git a/calypso/struct.go b/calypso/struct.go index 415a9c0263..3afb295a22 100644 --- a/calypso/struct.go +++ b/calypso/struct.go @@ -1,15 +1,22 @@ package calypso import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" "crypto/sha256" "fmt" + "io" + "go.dedis.ch/cothority/v3" "go.dedis.ch/cothority/v3/byzcoin" "go.dedis.ch/cothority/v3/darc" "go.dedis.ch/kyber/v3" "go.dedis.ch/kyber/v3/suites" + "go.dedis.ch/kyber/v3/util/random" "go.dedis.ch/kyber/v3/xof/keccak" "go.dedis.ch/onet/v3/network" + "golang.org/x/xerrors" ) func init() { @@ -68,6 +75,20 @@ func NewWrite(suite suites.Suite, ltsid byzcoin.InstanceID, writeDarc darc.ID, X return wr } +// NewWriteData is like NewWrite, +// but it encrypts the data with a random key and adds the data to the Write +// structure. +func NewWriteData(suite suites.Suite, ltsid byzcoin.InstanceID, + writeDarc darc.ID, X kyber.Point, data []byte) (wr *Write, err error) { + key := random.Bits(192, true, random.New()) + wr = NewWrite(suite, ltsid, writeDarc, X, key) + wr.Data, err = AeadSeal(key, data) + if err != nil { + return nil, xerrors.Errorf("couldn't seal data: %v", err) + } + return +} + // CheckProof verifies that the write-request has actually been created with // somebody having access to the secret key. func (wr *Write) CheckProof(suite suite, writeID darc.ID) error { @@ -97,6 +118,60 @@ func (wr *Write) CheckProof(suite suite, writeID darc.ID) error { "%s\n%s", e.String(), wr.E.String()) } +// Decrypt calls AeadOpen to decrypt the data with the given key. +func (wr *Write) Decrypt(key []byte) ([]byte, error) { + return AeadOpen(key, wr.Data) +} + +// This suggested length is from https://godoc.org/crypto/cipher#NewGCM example +const nonceLen = 12 + +// AeadSeal encrypts the given plaintext with the given key. +// It adds a 12-byte nonce to the ciphertext. +func AeadSeal(symKey, data []byte) ([]byte, error) { + block, err := aes.NewCipher(symKey) + if err != nil { + return nil, + xerrors.Errorf("creating aes cipher block instance: %v", err) + } + + // Never use more than 2^32 random nonces with a given key because of the risk of a repeat. + nonce := make([]byte, nonceLen) + _, err = io.ReadFull(rand.Reader, nonce) + if err != nil { + return nil, xerrors.Errorf("reading nonce: %v", err) + } + + aesgcm, err := cipher.NewGCM(block) + if err != nil { + return nil, xerrors.Errorf("creating aesgcm instance: %v", err) + } + encData := aesgcm.Seal(nil, nonce, data, nil) + encData = append(encData, nonce...) + return encData, nil +} + +// AeadOpen decrypts a given ciphertext with the given key. +func AeadOpen(key, ciphertext []byte) ([]byte, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, + xerrors.Errorf("creating aes cipher block instance: %v", err) + } + + aesgcm, err := cipher.NewGCM(block) + if err != nil { + return nil, xerrors.Errorf("creating aesgcm instance: %v", err) + } + + if len(ciphertext) < 12 { + return nil, xerrors.New("ciphertext too short") + } + nonce := ciphertext[len(ciphertext)-nonceLen:] + out, err := aesgcm.Open(nil, nonce, ciphertext[0:len(ciphertext)-nonceLen], nil) + return out, cothority.ErrorOrNil(err, "decrypting ciphertext") +} + type newLtsConfig struct { byzcoin.Proof } diff --git a/darc/darc.go b/darc/darc.go index 9ed13e286a..1539b9e521 100644 --- a/darc/darc.go +++ b/darc/darc.go @@ -868,6 +868,8 @@ func (id Identity) Type() int { return 3 case id.EvmContract != nil: return 4 + case id.ECDSA != nil: + return 5 } return -1 } diff --git a/darc/darc_test.go b/darc/darc_test.go index 59a91c9f88..69b39205d8 100644 --- a/darc/darc_test.go +++ b/darc/darc_test.go @@ -1,9 +1,12 @@ package darc import ( + "crypto/ecdsa" + "crypto/elliptic" "encoding/hex" "errors" "fmt" + "math/big" "net/url" "strings" "testing" @@ -751,22 +754,25 @@ func TestParseIdentity(t *testing.T) { } // Test any identity -func testIdentity(t *testing.T, sig Signer) { +func testIdentity(t *testing.T, id Identity) { msg := []byte(`Hello World`) - //signed, err := sig.Sign(msg) - //require.NoError(t, err) - - //Public Key: 0ab07149ce744429b7755e6a3d4c277d2f7a2a61ad93cfd18d6aa652e92069db - //Signature: 9626e46f0be4b96c65742e2a81945536fff6a23fad1a40b9cb0b6030cebaac293b6caf7cdc569e689a92db81176f380f6045cc72cd013f9cd4a1cb5bfa077d00 - signed, _ := hex.DecodeString("9626e46f0be4b96c65742e2a81945536fff6a23fad1a40b9cb0b6030cebaac293b6caf7cdc569e689a92db81176f380f6045cc72cd013f9cd4a1cb5bfa077d00") - in := "ed25519:0ab07149ce744429b7755e6a3d4c277d2f7a2a61ad93cfd18d6aa652e92069db" - id, _ := ParseIdentity(in) - //id := sig.Identity() + + //Signature from code example go-tsm-sdk corresponding to ecdsa public key example + signed, _ := hex.DecodeString("304402204f0b20a44efacec7b0514683233a79552026fe80e468078f6fed6cfe3f3e8a0402201eb12db7f6fe0828cafe8b0a032a37ff377b342799cfe77cfbac40c8ec1fa9e8") + require.NoError(t, id.Verify(msg, signed)) require.Error(t, id.Verify([]byte("wrong message"), signed)) } // Test the different identities available - currently only Ed25519. func TestIdentities(t *testing.T) { - testIdentity(t, NewSignerEd25519(nil, nil)) + //Ecdsa public key example + var x, _ = new(big.Int).SetString("25613385885653880697990944418179706546134037329992108968315147853972798913688", 10) + var y, _ = new(big.Int).SetString("74946767262888349555270609195205284686604880870734462312238891495596941025713", 10) + pk := ecdsa.PublicKey{ + Curve: elliptic.P256(), + X: x, + Y: y, + } + testIdentity(t, NewIdentityECDSA(pk)) } From 3632b200e90abf857efef61b801c6c2e142b58cb Mon Sep 17 00:00:00 2001 From: pm-duokey Date: Tue, 21 Dec 2021 02:19:15 -0800 Subject: [PATCH 04/10] ECDSA signer --- darc/darc.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/darc/darc.go b/darc/darc.go index 1539b9e521..8f5e09dc61 100644 --- a/darc/darc.go +++ b/darc/darc.go @@ -1500,8 +1500,14 @@ func (kcs SignerX509EC) Sign(msg []byte) ([]byte, error) { return nil, errors.New("not yet implemented") } -func NewSignerECDSA() Signer { - return Signer{} +// new signer creates a signer only with a public key used to verify signatures +func NewSignerECDSA(public ecdsa.PublicKey) Signer { + if public.X == nil { + return Signer{} + } + return Signer{ECDSA: &SignerECDSA{ + PublicKey: public, + }} } //TODO From ec6cdb2c85d7d333a22f670e567e52bf350711da Mon Sep 17 00:00:00 2001 From: pm-duokey Date: Wed, 22 Dec 2021 00:45:56 -0800 Subject: [PATCH 05/10] removing superflue import --- calypso/api_test.go | 16 +++++++++++++++- calypso/contracts.go | 1 - 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/calypso/api_test.go b/calypso/api_test.go index 119cbb1f18..81c749ace8 100644 --- a/calypso/api_test.go +++ b/calypso/api_test.go @@ -1,7 +1,10 @@ package calypso import ( + "crypto/ecdsa" + "crypto/elliptic" "encoding/binary" + "math/big" "testing" "time" @@ -227,9 +230,18 @@ func TestClient_Calypso_Simple(t *testing.T) { _, roster, _ := l.GenTree(3, true) defer l.CloseAll() + //create an example public key + var x, _ = new(big.Int).SetString("25613385885653880697990944418179706546134037329992108968315147853972798913688", 10) + var y, _ = new(big.Int).SetString("74946767262888349555270609195205284686604880870734462312238891495596941025713", 10) + pk := ecdsa.PublicKey{ + Curve: elliptic.P256(), + X: x, + Y: y, + } + admin := darc.NewSignerEd25519(nil, nil) adminCt := uint64(1) - user := darc.NewSignerEd25519(nil, nil) + user := darc.NewSignerECDSA(pk) // Initialise the genesis message and send it to the service. // The admin has the privilege to spawn darcs msg, err := byzcoin.DefaultGenesisMsg(byzcoin.CurrentVersion, roster, @@ -293,6 +305,7 @@ func TestClient_Calypso_Simple(t *testing.T) { digest := wrTx.Instructions.Hash() // This signature can be replaced by an external signature. + //TODO add sepior signature of digest here signature, err := user.Sign(digest) require.NoError(t, err) wrTx.Instructions[0].Signatures = [][]byte{signature} @@ -315,6 +328,7 @@ func TestClient_Calypso_Simple(t *testing.T) { digest = readTx.Instructions.Hash() // This signature can be replaced by an external signature + // TODO add signature on digest from MPC nodes signature, err = user.Sign(digest) require.NoError(t, err) readTx.Instructions[0].Signatures = [][]byte{signature} diff --git a/calypso/contracts.go b/calypso/contracts.go index bec3f3ebcf..15af2a21b6 100644 --- a/calypso/contracts.go +++ b/calypso/contracts.go @@ -2,7 +2,6 @@ package calypso import ( "fmt" - "go.dedis.ch/kyber/v3" "strings" "go.dedis.ch/cothority/v3" From b63fc6fd1a75c15fae5a24cc2bcc2c5bcd7c82c0 Mon Sep 17 00:00:00 2001 From: pm-duokey Date: Wed, 22 Dec 2021 06:59:35 -0800 Subject: [PATCH 06/10] ecdsa calypso/api_test.go error --- calypso/api_test.go | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/calypso/api_test.go b/calypso/api_test.go index 81c749ace8..a63631e806 100644 --- a/calypso/api_test.go +++ b/calypso/api_test.go @@ -3,8 +3,8 @@ package calypso import ( "crypto/ecdsa" "crypto/elliptic" + "crypto/rand" "encoding/binary" - "math/big" "testing" "time" @@ -231,17 +231,13 @@ func TestClient_Calypso_Simple(t *testing.T) { defer l.CloseAll() //create an example public key - var x, _ = new(big.Int).SetString("25613385885653880697990944418179706546134037329992108968315147853972798913688", 10) - var y, _ = new(big.Int).SetString("74946767262888349555270609195205284686604880870734462312238891495596941025713", 10) - pk := ecdsa.PublicKey{ - Curve: elliptic.P256(), - X: x, - Y: y, - } + random := rand.Reader + p, err := ecdsa.GenerateKey(elliptic.P256(), random) + require.NoError(t, err) admin := darc.NewSignerEd25519(nil, nil) adminCt := uint64(1) - user := darc.NewSignerECDSA(pk) + user := darc.NewSignerECDSA(p.PublicKey) // Initialise the genesis message and send it to the service. // The admin has the privilege to spawn darcs msg, err := byzcoin.DefaultGenesisMsg(byzcoin.CurrentVersion, roster, @@ -268,7 +264,7 @@ func TestClient_Calypso_Simple(t *testing.T) { adminCt++ require.NoError(t, err) //If no error, assign it - calypsoClient.ltsReply = ltsReply + //calypsoClient.ltsReply = ltsReply //Create a signer darc userDarc := darc.NewDarc(darc.InitRules([]darc.Identity{user.Identity()}, @@ -289,8 +285,8 @@ func TestClient_Calypso_Simple(t *testing.T) { data := []byte("Some secret data - or the user's private key") // Create a Write structure write1, err := NewWriteData(cothority.Suite, - calypsoClient.ltsReply.InstanceID, - userDarc.GetBaseID(), calypsoClient.ltsReply.X, data) + ltsReply.InstanceID, + userDarc.GetBaseID(), ltsReply.X, data) require.NoError(t, err) // Create a write-instance and send it to Byzcoin - here @@ -306,7 +302,7 @@ func TestClient_Calypso_Simple(t *testing.T) { // This signature can be replaced by an external signature. //TODO add sepior signature of digest here - signature, err := user.Sign(digest) + signature, err := ecdsa.SignASN1(random, p, digest) require.NoError(t, err) wrTx.Instructions[0].Signatures = [][]byte{signature} @@ -329,7 +325,7 @@ func TestClient_Calypso_Simple(t *testing.T) { // This signature can be replaced by an external signature // TODO add signature on digest from MPC nodes - signature, err = user.Sign(digest) + signature, err = ecdsa.SignASN1(random, p, digest) require.NoError(t, err) readTx.Instructions[0].Signatures = [][]byte{signature} readID := readTx.Instructions[0].DeriveID("") @@ -345,7 +341,7 @@ func TestClient_Calypso_Simple(t *testing.T) { dk, err := calypsoClient.DecryptKey(&DecryptKey{Read: *proofRd, Write: *proofWr}) require.NoError(t, err) - require.True(t, dk.X.Equal(calypsoClient.ltsReply.X)) + require.True(t, dk.X.Equal(ltsReply.X)) keyCopy, err := dk.RecoverKey(ephemeral.Private) require.NoError(t, err) var wrCopy Write From 2d788960e93e2bd4a01d7a8e192c1394fbe2db2e Mon Sep 17 00:00:00 2001 From: Linus Gasser Date: Thu, 23 Dec 2021 11:01:38 +0100 Subject: [PATCH 07/10] Add marshalling and a test --- calypso/api_test.go | 6 +-- calypso/protocol/ocs_test.go | 2 +- darc/darc.go | 93 ++++++++++++++++++++++-------------- darc/darc_test.go | 25 ++++++++-- darc/proto.go | 14 +++--- 5 files changed, 89 insertions(+), 51 deletions(-) diff --git a/calypso/api_test.go b/calypso/api_test.go index a63631e806..3a32e76b4c 100644 --- a/calypso/api_test.go +++ b/calypso/api_test.go @@ -207,9 +207,9 @@ func TestClient_Calypso(t *testing.T) { // Make sure you can't decrypt with non-matching proofs _, err = calypsoClient.DecryptKey(&DecryptKey{Read: *prRe1, Write: *prWr2}) - require.NotNil(t, err) + require.Error(t, err) _, err = calypsoClient.DecryptKey(&DecryptKey{Read: *prRe2, Write: *prWr1}) - require.NotNil(t, err) + require.Error(t, err) // Make sure you can actually decrypt dk1, err := calypsoClient.DecryptKey(&DecryptKey{Read: *prRe1, Write: *prWr1}) @@ -237,7 +237,7 @@ func TestClient_Calypso_Simple(t *testing.T) { admin := darc.NewSignerEd25519(nil, nil) adminCt := uint64(1) - user := darc.NewSignerECDSA(p.PublicKey) + user := darc.NewSignerTSM(p.PublicKey) // Initialise the genesis message and send it to the service. // The admin has the privilege to spawn darcs msg, err := byzcoin.DefaultGenesisMsg(byzcoin.CurrentVersion, roster, diff --git a/calypso/protocol/ocs_test.go b/calypso/protocol/ocs_test.go index 24a83063fe..aab85e8803 100644 --- a/calypso/protocol/ocs_test.go +++ b/calypso/protocol/ocs_test.go @@ -252,7 +252,7 @@ func DecodeKey(suite kyber.Group, X kyber.Point, Cs []kyber.Point, XhatEnc kyber } key = append(key, keyPart...) } - return + return } // starts a new service. No function needed. diff --git a/darc/darc.go b/darc/darc.go index 8f5e09dc61..9caa51e91b 100644 --- a/darc/darc.go +++ b/darc/darc.go @@ -774,8 +774,10 @@ func (s Signer) Type() int { return 3 case s.EvmContract != nil: return 4 - case s.ECDSA != nil: + case s.DID != nil: return 5 + case s.TSM != nil: + return 6 default: return -1 } @@ -793,8 +795,8 @@ func (s Signer) Identity() Identity { return NewIdentityProxy(s.Proxy) case 4: return NewIdentityEvmContract(s.EvmContract) - case 5: - return NewIdentityECDSA(s.ECDSA.PublicKey) + case 6: + return NewIdentityTSM(s.TSM.PublicKey) default: return Identity{} } @@ -826,7 +828,7 @@ func (s Signer) GetPrivate() (kyber.Scalar, error) { switch s.Type() { case 1: return s.Ed25519.Secret, nil - case 0, 2, 3: + case 0, 2, 3, 4, 5, 6: return nil, errors.New("signer lacks a private key") default: return nil, errors.New("signer is of unknown type") @@ -850,6 +852,8 @@ func (id Identity) Equal(id2 *Identity) bool { return id.Proxy.Equal(id2.Proxy) case 4: return id.EvmContract.Equal(id2.EvmContract) + case 6: + return id.TSM.PublicKey.Equal(&id2.TSM.PublicKey) } return false } @@ -868,8 +872,10 @@ func (id Identity) Type() int { return 3 case id.EvmContract != nil: return 4 - case id.ECDSA != nil: + case id.DID != nil: return 5 + case id.TSM != nil: + return 6 } return -1 } @@ -877,19 +883,7 @@ func (id Identity) Type() int { // PrimaryIdentity returns true if the identity is a primary identity, which is // an identity that is associated with a concrete public/private key. func (id Identity) PrimaryIdentity() bool { - switch { - case id.Darc != nil: - return false - case id.Ed25519 != nil: - return true - case id.X509EC != nil: - return true - case id.Proxy != nil: - return true - case id.EvmContract != nil: - return true - } - return false + return id.Type() != 0 } // TypeString returns the string of the type of the identity. @@ -905,6 +899,10 @@ func (id Identity) TypeString() string { return "proxy" case 4: return "evm_contract" + case 5: + return "did" + case 6: + return "tsm" default: return "No identity" } @@ -925,6 +923,14 @@ func (id Identity) String() string { bevmString := hex.EncodeToString(id.EvmContract.BEvmID) addrString := id.EvmContract.Address.Hex() return fmt.Sprintf("%s:%s:%s", id.TypeString(), bevmString, addrString) + case 5: + return fmt.Sprintf("%s:%s", id.TypeString(), id.DID.DID) + case 6: + buf, err := id.TSM.MarshalBinary() + if err != nil { + panic("couldn't marshal TSM key: " + err.Error()) + } + return fmt.Sprintf("%s:%x", id.TypeString(), buf) default: return "No identity" } @@ -945,7 +951,7 @@ func (id Identity) Verify(msg, sig []byte) error { case 4: return id.EvmContract.Verify(msg, sig) case 5: - return id.ECDSA.Verify(msg, sig) + return id.TSM.Verify(msg, sig) default: return errors.New("unknown identity") } @@ -974,7 +980,7 @@ func (id Identity) GetPublicBytes() []byte { case 4: return id.EvmContract.Address[:] case 5: - buf := elliptic.Marshal(id.ECDSA.PublicKey.Curve, id.ECDSA.PublicKey.X, id.ECDSA.PublicKey.Y) + buf := elliptic.Marshal(id.TSM.PublicKey.Curve, id.TSM.PublicKey.X, id.TSM.PublicKey.Y) //TODO: add error check here? return buf default: @@ -1025,17 +1031,17 @@ func NewIdentityX509EC(public []byte) Identity { } } -// NewIdentityECDSA creates a new ECDSA identity struct given a public key -func NewIdentityECDSA(publicKey ecdsa.PublicKey) Identity { +// NewIdentityTSM creates a new TSM identity struct given a public key +func NewIdentityTSM(publicKey ecdsa.PublicKey) Identity { return Identity{ - ECDSA: &IdentityECDSA{ + TSM: &IdentityTSM{ PublicKey: publicKey, }, } } -//TODO make calls to tsm available -func (ide IdentityECDSA) Verify(msg []byte, sig []byte) error { +// Verify the signature of the identity. +func (ide IdentityTSM) Verify(msg []byte, sig []byte) error { hashMsg := sha256.Sum256(msg) valid := ecdsa.VerifyASN1(&ide.PublicKey, hashMsg[:], sig) if !valid { @@ -1044,6 +1050,21 @@ func (ide IdentityECDSA) Verify(msg []byte, sig []byte) error { return nil } +// MarshalBinary returns the compressed public key +func (ide IdentityTSM) MarshalBinary() ([]byte, error) { + return elliptic.MarshalCompressed(ide.PublicKey.Curve, ide.PublicKey.X, + ide.PublicKey.Y), nil +} + +// UnmarshalBinary copies the x and y coordinates from the compressed data +func (ide *IdentityTSM) UnmarshalBinary(data []byte) error { + x, y := elliptic.UnmarshalCompressed(elliptic.P256(), data) + ide.PublicKey.X = x + ide.PublicKey.Y = y + ide.PublicKey.Curve = elliptic.P256() + return nil +} + // NewIdentityProxy creates a new OpenID Connect identity struct. func NewIdentityProxy(s *SignerProxy) Identity { return Identity{ @@ -1152,8 +1173,8 @@ func ParseIdentity(in string) (Identity, error) { return parseIDProxy(fields[1]) case "evm_contract": return parseIDEvmContract(fields[1]) - case "secp256k1": - return parseIDECDSA(fields[1]) + case "tsm": + return parseIDTSM(fields[1]) default: return Identity{}, fmt.Errorf("unknown identity type %v", fields[0]) } @@ -1178,7 +1199,7 @@ func parseIDX509ec(in string) (Identity, error) { //necessary function, needs to be refactored only supports elliptic.P256 curve //needs to be tested Unmarshal might not work -func parseIDECDSA(in string) (Identity, error) { +func parseIDTSM(in string) (Identity, error) { id := make([]byte, hex.DecodedLen(len(in))) _, err := hex.Decode(id, []byte(in)) @@ -1192,7 +1213,7 @@ func parseIDECDSA(in string) (Identity, error) { if err != nil { return Identity{}, err } - return Identity{ECDSA: &IdentityECDSA{PublicKey: pubkey}}, nil + return Identity{TSM: &IdentityTSM{PublicKey: pubkey}}, nil } func parseIDDarc(in string) (Identity, error) { @@ -1500,19 +1521,21 @@ func (kcs SignerX509EC) Sign(msg []byte) ([]byte, error) { return nil, errors.New("not yet implemented") } -// new signer creates a signer only with a public key used to verify signatures -func NewSignerECDSA(public ecdsa.PublicKey) Signer { +// NewSignerTSM creates a signer only with a public key used to verify +// signatures +func NewSignerTSM(public ecdsa.PublicKey) Signer { if public.X == nil { return Signer{} } - return Signer{ECDSA: &SignerECDSA{ + return Signer{TSM: &SignerTSM{ PublicKey: public, }} } -//TODO -func (kcs SignerECDSA) Sign(msg []byte) ([]byte, error) { - //call tsm to sign +// Sign the message with the private key. +// As this is using the TSM, and we don't want cothority/darc to depend on +// TSM, we cannot sign here. +func (kcs SignerTSM) Sign(msg []byte) ([]byte, error) { return nil, errors.New("not yet implemented") } diff --git a/darc/darc_test.go b/darc/darc_test.go index 69b39205d8..0ef23e0632 100644 --- a/darc/darc_test.go +++ b/darc/darc_test.go @@ -757,16 +757,15 @@ func TestParseIdentity(t *testing.T) { func testIdentity(t *testing.T, id Identity) { msg := []byte(`Hello World`) - //Signature from code example go-tsm-sdk corresponding to ecdsa public key example + // Signature from code example go-tsm-sdk corresponding to tsm public + // key example signed, _ := hex.DecodeString("304402204f0b20a44efacec7b0514683233a79552026fe80e468078f6fed6cfe3f3e8a0402201eb12db7f6fe0828cafe8b0a032a37ff377b342799cfe77cfbac40c8ec1fa9e8") require.NoError(t, id.Verify(msg, signed)) require.Error(t, id.Verify([]byte("wrong message"), signed)) } -// Test the different identities available - currently only Ed25519. -func TestIdentities(t *testing.T) { - //Ecdsa public key example +func getTSMId() Identity { var x, _ = new(big.Int).SetString("25613385885653880697990944418179706546134037329992108968315147853972798913688", 10) var y, _ = new(big.Int).SetString("74946767262888349555270609195205284686604880870734462312238891495596941025713", 10) pk := ecdsa.PublicKey{ @@ -774,5 +773,21 @@ func TestIdentities(t *testing.T) { X: x, Y: y, } - testIdentity(t, NewIdentityECDSA(pk)) + return NewIdentityTSM(pk) +} + +// Test the different identities available - currently only Ed25519. +func TestIdentities(t *testing.T) { + // tsm public key example + testIdentity(t, getTSMId()) +} + +// Make sure Marshalling and Unmarshalling work +func TestTSM(t *testing.T) { + id := getTSMId() + buf, err := id.TSM.MarshalBinary() + require.NoError(t, err) + var id2 IdentityTSM + require.NoError(t, id2.UnmarshalBinary(buf)) + require.True(t, id.Equal(&Identity{TSM: &id2})) } diff --git a/darc/proto.go b/darc/proto.go index 46fbb02ada..aac0370985 100644 --- a/darc/proto.go +++ b/darc/proto.go @@ -73,8 +73,8 @@ type Identity struct { EvmContract *IdentityEvmContract // A claim signed by one of the keys in a DID Doc DID *IdentityDID - // Publik-key identity from an ECDSA key - ECDSA *IdentityECDSA + // Public-key identity from an ECDSA key + TSM *IdentityTSM } // IdentityEd25519 holds a Ed25519 public key (Point) @@ -82,8 +82,8 @@ type IdentityEd25519 struct { Point kyber.Point } -// IdentityECDSA holds a secp256k1 key (array of bytes) -type IdentityECDSA struct { +// IdentityTSM holds a secp256k1 key (array of bytes) +type IdentityTSM struct { PublicKey ecdsa.PublicKey } @@ -168,7 +168,7 @@ type Signer struct { Proxy *SignerProxy EvmContract *SignerEvmContract DID *SignerDID - ECDSA *SignerECDSA + TSM *SignerTSM } // SignerEd25519 holds a public and private keys necessary to sign Darcs @@ -184,9 +184,9 @@ type SignerX509EC struct { secret []byte } -// SignerECDSA holds a public and private keys necessary to sign Darcs, +// SignerTSM holds a public and private keys necessary to sign Darcs, // but the private key will not be given out. -type SignerECDSA struct { +type SignerTSM struct { PublicKey ecdsa.PublicKey PrivateKey ecdsa.PrivateKey } From fdfc3eb140ed404765f3015adb79d14547c5a4ae Mon Sep 17 00:00:00 2001 From: Linus Gasser Date: Thu, 23 Dec 2021 11:29:41 +0100 Subject: [PATCH 08/10] added tsm to darcs, too, but signature is failing --- byzcoin/transaction.go | 5 +++++ calypso/api_test.go | 7 ++++++- darc/darc.go | 2 ++ darc/expression/expression.go | 4 ++-- 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/byzcoin/transaction.go b/byzcoin/transaction.go index a0c28e1d7e..1b5f9987e2 100644 --- a/byzcoin/transaction.go +++ b/byzcoin/transaction.go @@ -451,9 +451,14 @@ func (instr Instruction) VerifyWithOption(st ReadOnlyStateTrie, msg []byte, ops // check the signature // Save the identities that provide good signatures identitiesWithCorrectSignatures := make([]string, 0) + log.Print("SignerIdentities:", instr.SignerIdentities) for i := range instr.Signatures { if err := instr.SignerIdentities[i].Verify(msg, instr.Signatures[i]); err == nil { + log.Printf("OK when checking %s with %x", msg, instr.Signatures[i]) identitiesWithCorrectSignatures = append(identitiesWithCorrectSignatures, instr.SignerIdentities[i].String()) + } else { + log.Printf("Failed when checking %s with %x", msg, + instr.Signatures[i]) } } diff --git a/calypso/api_test.go b/calypso/api_test.go index 3a32e76b4c..f67ee0beb3 100644 --- a/calypso/api_test.go +++ b/calypso/api_test.go @@ -5,6 +5,7 @@ import ( "crypto/elliptic" "crypto/rand" "encoding/binary" + "go.dedis.ch/onet/v3/log" "testing" "time" @@ -233,11 +234,12 @@ func TestClient_Calypso_Simple(t *testing.T) { //create an example public key random := rand.Reader p, err := ecdsa.GenerateKey(elliptic.P256(), random) - require.NoError(t, err) + //require.NoError(t, err) admin := darc.NewSignerEd25519(nil, nil) adminCt := uint64(1) user := darc.NewSignerTSM(p.PublicKey) + //user := darc.NewSignerEd25519(nil, nil) // Initialise the genesis message and send it to the service. // The admin has the privilege to spawn darcs msg, err := byzcoin.DefaultGenesisMsg(byzcoin.CurrentVersion, roster, @@ -303,8 +305,10 @@ func TestClient_Calypso_Simple(t *testing.T) { // This signature can be replaced by an external signature. //TODO add sepior signature of digest here signature, err := ecdsa.SignASN1(random, p, digest) + //signature, err := user.Sign(digest) require.NoError(t, err) wrTx.Instructions[0].Signatures = [][]byte{signature} + log.Printf("wrTx is: %+v", wrTx) // Send the transaction to ByzCoin _, err = calypsoClient.bcClient.AddTransactionAndWait(wrTx, 10) @@ -326,6 +330,7 @@ func TestClient_Calypso_Simple(t *testing.T) { // This signature can be replaced by an external signature // TODO add signature on digest from MPC nodes signature, err = ecdsa.SignASN1(random, p, digest) + //signature, err = user.Sign(digest) require.NoError(t, err) readTx.Instructions[0].Signatures = [][]byte{signature} readID := readTx.Instructions[0].DeriveID("") diff --git a/darc/darc.go b/darc/darc.go index 9caa51e91b..9b41441b69 100644 --- a/darc/darc.go +++ b/darc/darc.go @@ -42,6 +42,7 @@ import ( "encoding/hex" "errors" "fmt" + "go.dedis.ch/onet/v3/log" "math/big" "regexp" "strconv" @@ -1158,6 +1159,7 @@ func (id IdentityEvmContract) Verify(msg, s []byte) error { // ParseIdentity returns an Identity structure that matches // the given string. func ParseIdentity(in string) (Identity, error) { + log.Print("Parsing", in) fields := strings.SplitN(in, ":", 2) if len(fields) != 2 { return Identity{}, errors.New("missing identity type") diff --git a/darc/expression/expression.go b/darc/expression/expression.go index 7dd5bff7da..cb99140b04 100644 --- a/darc/expression/expression.go +++ b/darc/expression/expression.go @@ -6,7 +6,7 @@ the syntax we use is from: https://en.wikipedia.org/wiki/Extended_Backus%E2%80%9 expr = term, [ '&', term ]* term = factor, [ '|', factor ]* factor = '(', expr, ')' | id | openid - identity = (darc|ed25519|x509ec):[0-9a-fA-F]+ + identity = (darc|ed25519|x509ec|tsm):[0-9a-fA-F]+ proxy = proxy:[0-9a-fA-F]+:[^ \n\t]* evm_identity = evm_contract:[0-9a-fA-F]+:0x[0-9a-fA-F]+ attr = attr:[0-9a-zA-Z\-\_]+:[^ \n\t]* @@ -154,7 +154,7 @@ func (e Expr) AddAndElement(id string) Expr { func identity() parsec.Parser { return func(s parsec.Scanner) (parsec.ParsecNode, parsec.Scanner) { _, s = s.SkipAny(`^[ \n\t]+`) - p := parsec.Token(`(darc|ed25519|x509ec):[0-9a-fA-F]+`, "HEX") + p := parsec.Token(`(darc|ed25519|x509ec|tsm):[0-9a-fA-F]+`, "HEX") return p(s) } } From b67548c3e30e5d70c9338cf927743ae4dc0df28f Mon Sep 17 00:00:00 2001 From: Linus Gasser Date: Thu, 23 Dec 2021 12:19:27 +0100 Subject: [PATCH 09/10] Adding a TSM signer --- byzcoin/transaction.go | 5 ----- calypso/api_test.go | 17 +++-------------- darc/darc.go | 34 ++++++++++++++++++++-------------- darc/darc_test.go | 42 ++++++++++++++++++++++++++---------------- darc/proto.go | 1 - 5 files changed, 49 insertions(+), 50 deletions(-) diff --git a/byzcoin/transaction.go b/byzcoin/transaction.go index 1b5f9987e2..a0c28e1d7e 100644 --- a/byzcoin/transaction.go +++ b/byzcoin/transaction.go @@ -451,14 +451,9 @@ func (instr Instruction) VerifyWithOption(st ReadOnlyStateTrie, msg []byte, ops // check the signature // Save the identities that provide good signatures identitiesWithCorrectSignatures := make([]string, 0) - log.Print("SignerIdentities:", instr.SignerIdentities) for i := range instr.Signatures { if err := instr.SignerIdentities[i].Verify(msg, instr.Signatures[i]); err == nil { - log.Printf("OK when checking %s with %x", msg, instr.Signatures[i]) identitiesWithCorrectSignatures = append(identitiesWithCorrectSignatures, instr.SignerIdentities[i].String()) - } else { - log.Printf("Failed when checking %s with %x", msg, - instr.Signatures[i]) } } diff --git a/calypso/api_test.go b/calypso/api_test.go index f67ee0beb3..fde7d900c0 100644 --- a/calypso/api_test.go +++ b/calypso/api_test.go @@ -2,10 +2,7 @@ package calypso import ( "crypto/ecdsa" - "crypto/elliptic" - "crypto/rand" "encoding/binary" - "go.dedis.ch/onet/v3/log" "testing" "time" @@ -231,14 +228,9 @@ func TestClient_Calypso_Simple(t *testing.T) { _, roster, _ := l.GenTree(3, true) defer l.CloseAll() - //create an example public key - random := rand.Reader - p, err := ecdsa.GenerateKey(elliptic.P256(), random) - //require.NoError(t, err) - admin := darc.NewSignerEd25519(nil, nil) adminCt := uint64(1) - user := darc.NewSignerTSM(p.PublicKey) + user := darc.NewSignerTSM(ecdsa.PrivateKey{}) //user := darc.NewSignerEd25519(nil, nil) // Initialise the genesis message and send it to the service. // The admin has the privilege to spawn darcs @@ -304,11 +296,9 @@ func TestClient_Calypso_Simple(t *testing.T) { // This signature can be replaced by an external signature. //TODO add sepior signature of digest here - signature, err := ecdsa.SignASN1(random, p, digest) - //signature, err := user.Sign(digest) + signature, err := user.Sign(digest) require.NoError(t, err) wrTx.Instructions[0].Signatures = [][]byte{signature} - log.Printf("wrTx is: %+v", wrTx) // Send the transaction to ByzCoin _, err = calypsoClient.bcClient.AddTransactionAndWait(wrTx, 10) @@ -329,8 +319,7 @@ func TestClient_Calypso_Simple(t *testing.T) { // This signature can be replaced by an external signature // TODO add signature on digest from MPC nodes - signature, err = ecdsa.SignASN1(random, p, digest) - //signature, err = user.Sign(digest) + signature, err = user.Sign(digest) require.NoError(t, err) readTx.Instructions[0].Signatures = [][]byte{signature} readID := readTx.Instructions[0].DeriveID("") diff --git a/darc/darc.go b/darc/darc.go index 9b41441b69..fc47f1e9ba 100644 --- a/darc/darc.go +++ b/darc/darc.go @@ -34,6 +34,7 @@ import ( "bytes" "crypto/ecdsa" "crypto/elliptic" + "crypto/rand" "crypto/sha256" "crypto/sha512" "crypto/x509" @@ -797,7 +798,7 @@ func (s Signer) Identity() Identity { case 4: return NewIdentityEvmContract(s.EvmContract) case 6: - return NewIdentityTSM(s.TSM.PublicKey) + return NewIdentityTSM(s.TSM.PrivateKey.PublicKey) default: return Identity{} } @@ -819,6 +820,8 @@ func (s Signer) Sign(msg []byte) ([]byte, error) { return s.Proxy.Sign(msg) case 4: return s.EvmContract.Sign(msg) + case 6: + return s.TSM.Sign(msg) default: return nil, errors.New("unknown signer type") } @@ -951,7 +954,7 @@ func (id Identity) Verify(msg, sig []byte) error { return id.Proxy.Verify(msg, sig) case 4: return id.EvmContract.Verify(msg, sig) - case 5: + case 6: return id.TSM.Verify(msg, sig) default: return errors.New("unknown identity") @@ -980,7 +983,7 @@ func (id Identity) GetPublicBytes() []byte { return buf case 4: return id.EvmContract.Address[:] - case 5: + case 6: buf := elliptic.Marshal(id.TSM.PublicKey.Curve, id.TSM.PublicKey.X, id.TSM.PublicKey.Y) //TODO: add error check here? return buf @@ -1043,8 +1046,7 @@ func NewIdentityTSM(publicKey ecdsa.PublicKey) Identity { // Verify the signature of the identity. func (ide IdentityTSM) Verify(msg []byte, sig []byte) error { - hashMsg := sha256.Sum256(msg) - valid := ecdsa.VerifyASN1(&ide.PublicKey, hashMsg[:], sig) + valid := ecdsa.VerifyASN1(&ide.PublicKey, msg, sig) if !valid { return errors.New("Signature failed to verify") } @@ -1523,22 +1525,26 @@ func (kcs SignerX509EC) Sign(msg []byte) ([]byte, error) { return nil, errors.New("not yet implemented") } -// NewSignerTSM creates a signer only with a public key used to verify -// signatures -func NewSignerTSM(public ecdsa.PublicKey) Signer { - if public.X == nil { - return Signer{} +// NewSignerTSM creates a tsm signer with a SECP256K1 key. +// If a nil key is given, then a random key is generated. +func NewSignerTSM(private ecdsa.PrivateKey) Signer { + if private.D == nil { + priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + panic("couldn't generate key: " + err.Error()) + } + private = *priv } return Signer{TSM: &SignerTSM{ - PublicKey: public, + PrivateKey: private, }} } // Sign the message with the private key. -// As this is using the TSM, and we don't want cothority/darc to depend on -// TSM, we cannot sign here. +// This is not really possible with the TSM signer, +// so this is mostly useful for testing. func (kcs SignerTSM) Sign(msg []byte) ([]byte, error) { - return nil, errors.New("not yet implemented") + return ecdsa.SignASN1(rand.Reader, &kcs.PrivateKey, msg) } // NewSignerProxy creates a new SignerProxy. When Sign is called, the getSignature diff --git a/darc/darc_test.go b/darc/darc_test.go index 0ef23e0632..c907ab9450 100644 --- a/darc/darc_test.go +++ b/darc/darc_test.go @@ -3,6 +3,7 @@ package darc import ( "crypto/ecdsa" "crypto/elliptic" + "crypto/sha256" "encoding/hex" "errors" "fmt" @@ -754,18 +755,23 @@ func TestParseIdentity(t *testing.T) { } // Test any identity -func testIdentity(t *testing.T, id Identity) { - msg := []byte(`Hello World`) - - // Signature from code example go-tsm-sdk corresponding to tsm public - // key example - signed, _ := hex.DecodeString("304402204f0b20a44efacec7b0514683233a79552026fe80e468078f6fed6cfe3f3e8a0402201eb12db7f6fe0828cafe8b0a032a37ff377b342799cfe77cfbac40c8ec1fa9e8") - +func testIdentity(t *testing.T, sig Signer) { + msg := []byte("something secret") + signed, err := sig.Sign(msg) + require.NoError(t, err) + id := sig.Identity() require.NoError(t, id.Verify(msg, signed)) require.Error(t, id.Verify([]byte("wrong message"), signed)) } -func getTSMId() Identity { +// Test the different identities available - currently only Ed25519. +func TestIdentities(t *testing.T) { + testIdentity(t, NewSignerEd25519(nil, nil)) + testIdentity(t, NewSignerTSM(ecdsa.PrivateKey{})) +} + +// Test a signature from the TSM +func TestTSMSignature(t *testing.T) { var x, _ = new(big.Int).SetString("25613385885653880697990944418179706546134037329992108968315147853972798913688", 10) var y, _ = new(big.Int).SetString("74946767262888349555270609195205284686604880870734462312238891495596941025713", 10) pk := ecdsa.PublicKey{ @@ -773,18 +779,22 @@ func getTSMId() Identity { X: x, Y: y, } - return NewIdentityTSM(pk) -} + id := NewIdentityTSM(pk) -// Test the different identities available - currently only Ed25519. -func TestIdentities(t *testing.T) { - // tsm public key example - testIdentity(t, getTSMId()) + msg := []byte(`Hello World`) + digest := sha256.Sum256(msg) + + // Signature from code example go-tsm-sdk corresponding to tsm public + // key example + signed, _ := hex.DecodeString("304402204f0b20a44efacec7b0514683233a79552026fe80e468078f6fed6cfe3f3e8a0402201eb12db7f6fe0828cafe8b0a032a37ff377b342799cfe77cfbac40c8ec1fa9e8") + + require.NoError(t, id.Verify(digest[:], signed)) + require.Error(t, id.Verify([]byte("wrong message"), signed)) } // Make sure Marshalling and Unmarshalling work -func TestTSM(t *testing.T) { - id := getTSMId() +func TestTSMMarshalling(t *testing.T) { + id := NewSignerTSM(ecdsa.PrivateKey{}).Identity() buf, err := id.TSM.MarshalBinary() require.NoError(t, err) var id2 IdentityTSM diff --git a/darc/proto.go b/darc/proto.go index aac0370985..97da248062 100644 --- a/darc/proto.go +++ b/darc/proto.go @@ -187,7 +187,6 @@ type SignerX509EC struct { // SignerTSM holds a public and private keys necessary to sign Darcs, // but the private key will not be given out. type SignerTSM struct { - PublicKey ecdsa.PublicKey PrivateKey ecdsa.PrivateKey } From a06494a52a271fb3e707964c29c1896844418742 Mon Sep 17 00:00:00 2001 From: pm-duokey Date: Fri, 4 Mar 2022 10:45:35 +0100 Subject: [PATCH 10/10] TestClient_Calypso_Simple --- calypso/api_test.go | 198 +++++++++++++++++++++++--------------------- 1 file changed, 104 insertions(+), 94 deletions(-) diff --git a/calypso/api_test.go b/calypso/api_test.go index fde7d900c0..ccd34a20d2 100644 --- a/calypso/api_test.go +++ b/calypso/api_test.go @@ -2,6 +2,8 @@ package calypso import ( "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" "encoding/binary" "testing" "time" @@ -205,9 +207,9 @@ func TestClient_Calypso(t *testing.T) { // Make sure you can't decrypt with non-matching proofs _, err = calypsoClient.DecryptKey(&DecryptKey{Read: *prRe1, Write: *prWr2}) - require.Error(t, err) + require.NotNil(t, err) _, err = calypsoClient.DecryptKey(&DecryptKey{Read: *prRe2, Write: *prWr1}) - require.Error(t, err) + require.NotNil(t, err) // Make sure you can actually decrypt dk1, err := calypsoClient.DecryptKey(&DecryptKey{Read: *prRe1, Write: *prWr1}) @@ -223,15 +225,20 @@ func TestClient_Calypso(t *testing.T) { // Tests the Calypso system with a simple write/read scenario. // But it does the signing outside of the `Read` and `Write` methods for // integration of the MPC signing by OneKey. -func TestClient_Calypso_Simple(t *testing.T) { +func BenchmarkClient_Calypso_Simple(b *testing.B) { + b.StopTimer() l := onet.NewTCPTest(cothority.Suite) _, roster, _ := l.GenTree(3, true) defer l.CloseAll() + //create an example public key + random := rand.Reader + p, err := ecdsa.GenerateKey(elliptic.P256(), random) + require.NoError(b, err) + admin := darc.NewSignerEd25519(nil, nil) adminCt := uint64(1) - user := darc.NewSignerTSM(ecdsa.PrivateKey{}) - //user := darc.NewSignerEd25519(nil, nil) + user := darc.NewIdentityTSM(p.PublicKey) // Initialise the genesis message and send it to the service. // The admin has the privilege to spawn darcs msg, err := byzcoin.DefaultGenesisMsg(byzcoin.CurrentVersion, roster, @@ -239,109 +246,112 @@ func TestClient_Calypso_Simple(t *testing.T) { admin.Identity()) msg.BlockInterval = 500 * time.Millisecond - require.NoError(t, err) + require.NoError(b, err) // The darc inside it should be valid. gDarc := msg.GenesisDarc - require.Nil(t, gDarc.Verify(true)) + require.Nil(b, gDarc.Verify(true)) //Create Ledger c, _, err := byzcoin.NewLedger(msg, false) - require.NoError(t, err) + require.NoError(b, err) //Create a Calypso Client (Byzcoin + Onet) calypsoClient := NewClient(c) //Create the LTS for _, who := range roster.List { err := calypsoClient.Authorize(who, c.ID) - require.NoError(t, err) + require.NoError(b, err) } ltsReply, err := calypsoClient.CreateLTS(roster, gDarc.GetBaseID(), []darc.Signer{admin}, []uint64{adminCt}) adminCt++ - require.NoError(t, err) + require.NoError(b, err) //If no error, assign it //calypsoClient.ltsReply = ltsReply - + b.StartTimer() //Create a signer darc - userDarc := darc.NewDarc(darc.InitRules([]darc.Identity{user.Identity()}, - []darc.Identity{user.Identity()}), []byte("Provider1")) - // user can read and write. - // This can be changed to two different public keys. - err = userDarc.Rules.AddRule(darc.Action("spawn:"+ContractWriteID), - expression.InitOrExpr(user.Identity().String())) - require.NoError(t, err) - err = userDarc.Rules.AddRule(darc.Action("spawn:"+ContractReadID), - expression.InitOrExpr(user.Identity().String())) - require.NoError(t, err) - require.NotNil(t, userDarc) - _, err = calypsoClient.SpawnDarc(admin, adminCt, gDarc, *userDarc, 10) - adminCt++ - require.NoError(t, err) - - data := []byte("Some secret data - or the user's private key") - // Create a Write structure - write1, err := NewWriteData(cothority.Suite, - ltsReply.InstanceID, - userDarc.GetBaseID(), ltsReply.X, data) - require.NoError(t, err) - - // Create a write-instance and send it to Byzcoin - here - // the instruction and the transaction is created manually, - // so that an external signer can sign the hash of the instruction. - wrInst, err := ContractWriteSpawnInstruction(write1, userDarc) - require.NoError(t, err) - wrInst.SignerCounter = []uint64{1} - wrInst.SignerIdentities = []darc.Identity{user.Identity()} - wrTx, err := calypsoClient.bcClient.CreateTransaction(*wrInst) - require.NoError(t, err) - digest := wrTx.Instructions.Hash() - - // This signature can be replaced by an external signature. - //TODO add sepior signature of digest here - signature, err := user.Sign(digest) - require.NoError(t, err) - wrTx.Instructions[0].Signatures = [][]byte{signature} - - // Send the transaction to ByzCoin - _, err = calypsoClient.bcClient.AddTransactionAndWait(wrTx, 10) - require.NoError(t, err) - wrID := wrTx.Instructions[0].DeriveID("") - proofWr, err := calypsoClient.WaitProof(wrID, time.Second, nil) - require.NoError(t, err) - - // Create a read-instance and send it to ByzCoin. - ephemeral := key.NewKeyPair(cothority.Suite) - readInst, err := ContractReadSpawnInstruction(wrID, ephemeral.Public) - require.NoError(t, err) - readInst.SignerCounter = []uint64{2} - readInst.SignerIdentities = []darc.Identity{user.Identity()} - readTx, err := calypsoClient.bcClient.CreateTransaction(*readInst) - require.NoError(t, err) - digest = readTx.Instructions.Hash() - - // This signature can be replaced by an external signature - // TODO add signature on digest from MPC nodes - signature, err = user.Sign(digest) - require.NoError(t, err) - readTx.Instructions[0].Signatures = [][]byte{signature} - readID := readTx.Instructions[0].DeriveID("") - - // Send the transaction to ByzCoin - _, err = calypsoClient.bcClient.AddTransactionAndWait(readTx, 10) - require.NoError(t, err) - proofRd, err := calypsoClient.WaitProof(readID, time.Second, - nil) - require.NoError(t, err) - - // Make sure you can actually decrypt - dk, err := calypsoClient.DecryptKey(&DecryptKey{Read: *proofRd, - Write: *proofWr}) - require.NoError(t, err) - require.True(t, dk.X.Equal(ltsReply.X)) - keyCopy, err := dk.RecoverKey(ephemeral.Private) - require.NoError(t, err) - var wrCopy Write - require.NoError(t, proofWr.VerifyAndDecode(cothority.Suite, ContractWriteID, - &wrCopy)) - dataDecrypt, err := wrCopy.Decrypt(keyCopy) - require.NoError(t, err) - require.Equal(t, data, dataDecrypt) + for n := 0; n < b.N; n++ { + + userDarc := darc.NewDarc(darc.InitRules([]darc.Identity{user}, + []darc.Identity{user}), []byte("Provider1")) + // user can read and write. + // This can be changed to two different public keys. + err = userDarc.Rules.AddRule(darc.Action("spawn:"+ContractWriteID), + expression.InitOrExpr(user.String())) + require.NoError(b, err) + err = userDarc.Rules.AddRule(darc.Action("spawn:"+ContractReadID), + expression.InitOrExpr(user.String())) + require.NoError(b, err) + require.NotNil(b, userDarc) + _, err = calypsoClient.SpawnDarc(admin, adminCt, gDarc, *userDarc, 10) + adminCt++ + require.NoError(b, err) + + data := []byte("johns_private_key") + // Create a Write structure + write1, err := NewWriteData(cothority.Suite, + ltsReply.InstanceID, + userDarc.GetBaseID(), ltsReply.X, data) + require.NoError(b, err) + + // Create a write-instance and send it to Byzcoin - here + // the instruction and the transaction is created manually, + // so that an external signer can sign the hash of the instruction. + wrInst, err := ContractWriteSpawnInstruction(write1, userDarc) + require.NoError(b, err) + wrInst.SignerCounter = []uint64{1} + wrInst.SignerIdentities = []darc.Identity{user} + wrTx, err := calypsoClient.bcClient.CreateTransaction(*wrInst) + require.NoError(b, err) + digest := wrTx.Instructions.Hash() + + // This signature can be replaced by an external signature. + //TODO add sepior signature of digest here + signature, err := ecdsa.SignASN1(random, p, digest) + require.NoError(b, err) + wrTx.Instructions[0].Signatures = [][]byte{signature} + + // Send the transaction to ByzCoin + _, err = calypsoClient.bcClient.AddTransactionAndWait(wrTx, 10) + require.NoError(b, err) + wrID := wrTx.Instructions[0].DeriveID("") + proofWr, err := calypsoClient.WaitProof(wrID, time.Second, nil) + require.NoError(b, err) + + // Create a read-instance and send it to ByzCoin. + ephemeral := key.NewKeyPair(cothority.Suite) + readInst, err := ContractReadSpawnInstruction(wrID, ephemeral.Public) + require.NoError(b, err) + readInst.SignerCounter = []uint64{2} + readInst.SignerIdentities = []darc.Identity{user} + readTx, err := calypsoClient.bcClient.CreateTransaction(*readInst) + require.NoError(b, err) + digest = readTx.Instructions.Hash() + + // This signature can be replaced by an external signature + // TODO add signature on digest from MPC nodes + signature, err = ecdsa.SignASN1(random, p, digest) + require.NoError(b, err) + readTx.Instructions[0].Signatures = [][]byte{signature} + readID := readTx.Instructions[0].DeriveID("") + + // Send the transaction to ByzCoin + _, err = calypsoClient.bcClient.AddTransactionAndWait(readTx, 10) + require.NoError(b, err) + proofRd, err := calypsoClient.WaitProof(readID, time.Second, + nil) + require.NoError(b, err) + + // Make sure you can actually decrypt + dk, err := calypsoClient.DecryptKey(&DecryptKey{Read: *proofRd, + Write: *proofWr}) + require.NoError(b, err) + require.True(b, dk.X.Equal(ltsReply.X)) + keyCopy, err := dk.RecoverKey(ephemeral.Private) + require.NoError(b, err) + var wrCopy Write + require.NoError(b, proofWr.VerifyAndDecode(cothority.Suite, ContractWriteID, + &wrCopy)) + dataDecrypt, err := wrCopy.Decrypt(keyCopy) + require.NoError(b, err) + require.Equal(b, data, dataDecrypt) + } }