[client:client] implemented 'Send(io.Writer)' [client:client.internal] implemented 'generateRequest', 'generateKeyWithConstraints', 'migrate'
This commit is contained in:
parent
fdab12841c
commit
3b282e397b
|
@ -6,6 +6,8 @@ import (
|
||||||
"git.xdrm.io/schastsp/client/keyset"
|
"git.xdrm.io/schastsp/client/keyset"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const DEBUG = false
|
||||||
|
|
||||||
|
|
||||||
/* (1) Structure
|
/* (1) Structure
|
||||||
---------------------------------------------------------*/
|
---------------------------------------------------------*/
|
||||||
|
@ -58,7 +60,22 @@ func New(ctx *context.T, saveDir string) (*T, error) {
|
||||||
* @return err<error> Error
|
* @return err<error> Error
|
||||||
*
|
*
|
||||||
---------------------------------------------------------*/
|
---------------------------------------------------------*/
|
||||||
func (c *T) Send(w io.Writer) error { return nil }
|
func (c *T) Send(w io.Writer) error {
|
||||||
|
|
||||||
|
/* (1) Generate the request */
|
||||||
|
var x1, x2 []byte;
|
||||||
|
|
||||||
|
err := c.generateRequest(x1, x2);
|
||||||
|
if err != nil { return err }
|
||||||
|
|
||||||
|
/* (2) Write request into writer */
|
||||||
|
_, err = w.Write(x1)
|
||||||
|
if err != nil { return err }
|
||||||
|
_, err = w.Write(x2)
|
||||||
|
if err != nil { return err }
|
||||||
|
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* (4) Receives and processes a response
|
/* (4) Receives and processes a response
|
||||||
|
|
|
@ -1,6 +1,13 @@
|
||||||
package client;
|
package client;
|
||||||
|
|
||||||
import "git.xdrm.io/schastsp/client/keyset"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"encoding/binary"
|
||||||
|
"git.xdrm.io/schastsp/lib/scha"
|
||||||
|
"git.xdrm.io/schastsp/lib/xor"
|
||||||
|
"git.xdrm.io/schastsp/lib/timeid"
|
||||||
|
"git.xdrm.io/schastsp/client/keyset"
|
||||||
|
)
|
||||||
|
|
||||||
/* (1) Updates 'key' and 'sync' with files
|
/* (1) Updates 'key' and 'sync' with files
|
||||||
*
|
*
|
||||||
|
@ -63,3 +70,200 @@ func (c *T) update(){
|
||||||
if err != nil { panic("Cannot store sync") }
|
if err != nil { panic("Cannot store sync") }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* (2) Migrate current key
|
||||||
|
*
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
func (c *T) migrateKey(){
|
||||||
|
|
||||||
|
var err error;
|
||||||
|
|
||||||
|
/* (1) Copy sync into key */
|
||||||
|
c.key = c.sync
|
||||||
|
|
||||||
|
/* (2) Regenerate sync */
|
||||||
|
c.sync, err = keyset.Create(c.ctx);
|
||||||
|
if err != nil { panic(err) }
|
||||||
|
|
||||||
|
/* (3) Store keysets to files */
|
||||||
|
c.update();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* (3) Generate a new key respecting mod constraints (timeid + migration)
|
||||||
|
*
|
||||||
|
* @return newKey<*keyset.T> New key if found
|
||||||
|
* NIL on error
|
||||||
|
*
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
func (c *T) generateKeyWithConstraints(){
|
||||||
|
|
||||||
|
/* Get current hash */
|
||||||
|
keyHash, err := c.key.Hash();
|
||||||
|
if err != nil { panic(err) }
|
||||||
|
|
||||||
|
|
||||||
|
/* Search key one is respects contraints */
|
||||||
|
for true {
|
||||||
|
|
||||||
|
/* (1) Get current time id
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
_, timeMod := timeid.Generate(c.ctx.Window())
|
||||||
|
|
||||||
|
|
||||||
|
/* (2) Generate a new sync
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
newKey, _ := keyset.Create(c.ctx);
|
||||||
|
|
||||||
|
|
||||||
|
/* (3) Check constraints
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
/* (1) Get next hash */
|
||||||
|
syncHash, err := newKey.Hash()
|
||||||
|
if err != nil { continue }
|
||||||
|
|
||||||
|
if DEBUG { fmt.Printf("+ hash is '%x'\n", keyHash); }
|
||||||
|
if DEBUG { fmt.Printf("+ next hash is '%x'\n", syncHash); }
|
||||||
|
|
||||||
|
/* (2) Get time mod difference (first byte) */
|
||||||
|
timeConstraintValue := xor.Byte(keyHash[0], syncHash[0]);
|
||||||
|
|
||||||
|
if DEBUG { fmt.Printf(" %.2x ^ %.2x = %.2x[%d] %% 2 = %d == %d ? %t\n", keyHash[0], syncHash[0], timeConstraintValue, timeConstraintValue, uint32(timeConstraintValue) % 2, timeMod, uint32(timeConstraintValue) % 2 == timeMod ) }
|
||||||
|
|
||||||
|
/* (4) Retry if invalid time constraint */
|
||||||
|
if uint32(timeConstraintValue) % 2 != timeMod {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (5) Get migration mod difference (second byte) */
|
||||||
|
migrationConstraintValue := xor.Byte(keyHash[1], syncHash[2]);
|
||||||
|
|
||||||
|
if DEBUG { fmt.Printf(" %.2x ^ %.2x = %.2x[%d] %% 3 = %d == %d ? %t\n", keyHash[1], syncHash[1], migrationConstraintValue, migrationConstraintValue, uint8(migrationConstraintValue) % 3, c.key.MigrationCode(), uint8(migrationConstraintValue) % 3 == c.key.MigrationCode() ) }
|
||||||
|
|
||||||
|
/* (6) Retry if invalid time constraint */
|
||||||
|
if uint8(migrationConstraintValue) % 3 != c.key.MigrationCode() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (7) Store new sync */
|
||||||
|
c.sync = newKey;
|
||||||
|
|
||||||
|
/* (8) Store keysets to files */
|
||||||
|
c.update()
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* (4) Generate the client request
|
||||||
|
*
|
||||||
|
* @x1<[]byte> Byte array to write into
|
||||||
|
* @x2<[]byte> Byte array to write into
|
||||||
|
*
|
||||||
|
* @return err<error> The error or NIL if not
|
||||||
|
*
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
func (c *T) generateRequest(x1 []byte, x2 []byte) error {
|
||||||
|
|
||||||
|
|
||||||
|
/* (1) Migrate if validated migration
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
if c.key.MigrationCode() == 3 {
|
||||||
|
c.migrateKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (2) Decrement and get useful hashes
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
/* (1) Decrement hash */
|
||||||
|
remainingHashes := c.key.Decrement()
|
||||||
|
c.update()
|
||||||
|
|
||||||
|
if DEBUG {
|
||||||
|
fmt.Printf("Remaining %x[%d] hashes\n", remainingHashes, remainingHashes)
|
||||||
|
fmt.Printf("Migration code is %d\n", c.key.MigrationCode())
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (2) Store current hash */
|
||||||
|
h0, err := c.key.Hash();
|
||||||
|
if err != nil { return err }
|
||||||
|
|
||||||
|
/* (3) Copy into next hash (same value) */
|
||||||
|
h1, err := c.key.Hash();
|
||||||
|
if err != nil { return err }
|
||||||
|
|
||||||
|
|
||||||
|
/* (3) New sync hash if key consumed
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
if c.key.MigrationCode() > 0 {
|
||||||
|
|
||||||
|
/* (1) Generate sync with constraints */
|
||||||
|
c.generateKeyWithConstraints();
|
||||||
|
|
||||||
|
/* (2) Notify key need for renewal */
|
||||||
|
c.key.MigrationCode(2);
|
||||||
|
|
||||||
|
/* (3) Store config */
|
||||||
|
c.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* (4) Manage time id
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
/* (1) Get current time id */
|
||||||
|
timeId, timeMod := timeid.Generate(c.ctx.Window())
|
||||||
|
|
||||||
|
/* (2) Convert time id to byte array */
|
||||||
|
timeIdBytes := make([]byte, 4)
|
||||||
|
binary.BigEndian.PutUint32(timeIdBytes, timeId)
|
||||||
|
|
||||||
|
/* (2) Get digest of time id */
|
||||||
|
hashedTimeId, err := scha.Hash(timeIdBytes, 1, nil, nil)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* (5) Calculate x1 and x2
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
/* (1) Calculate x1 = h ^ h(timeId) */
|
||||||
|
x1 = xor.ByteArray(h0, hashedTimeId)
|
||||||
|
|
||||||
|
if DEBUG {
|
||||||
|
fmt.Printf("\n=== x1 ===\n");
|
||||||
|
fmt.Printf(" hash is h0 = %x\n", h0)
|
||||||
|
fmt.Printf(" time id is n = %x[%d]\n", timeIdBytes, timeId)
|
||||||
|
fmt.Printf(" h(t) = %x\n", hashedTimeId)
|
||||||
|
fmt.Printf(" ---\n");
|
||||||
|
fmt.Printf(" x1 is h0+h(t) = %x\n", x1)
|
||||||
|
fmt.Printf(" ---\n");
|
||||||
|
fmt.Printf(" check x1+h(t) eq h0 = %x\n", xor.ByteArray(x1, hashedTimeId))
|
||||||
|
fmt.Printf(" check x1+h0 eq h(t) = %x\n", xor.ByteArray(x1, h0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (2) Calculate x2 = h ^ h(timeId) ^ timeMod */
|
||||||
|
x2 = xor.ByteArray(h1, hashedTimeId)
|
||||||
|
|
||||||
|
// do not add time mod if not code = 0
|
||||||
|
if c.key.MigrationCode() != 0 {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
x2[0] = xor.Byte(x2[0], byte(timeMod))
|
||||||
|
|
||||||
|
if DEBUG {
|
||||||
|
fmt.Printf("\n=== x2 ===\n");
|
||||||
|
fmt.Printf(" next is h1 = %x\n", h1)
|
||||||
|
fmt.Printf(" time mod is m = %x[%d]\n", timeMod, timeMod)
|
||||||
|
fmt.Printf(" h(t) = %x\n", hashedTimeId)
|
||||||
|
fmt.Printf(" ---\n");
|
||||||
|
fmt.Printf(" x2 is h1+h(t)+m = %x\n", x2)
|
||||||
|
fmt.Printf(" ---\n");
|
||||||
|
fmt.Printf(" check x2+x1 %% 2 eq m = %d (%t)\n", uint8(xor.ByteArray(x1,x2)[0] % 2), xor.ByteArray(x1,x2)[0] % 2 == byte(timeMod))
|
||||||
|
fmt.Printf(" check x2+x1 %% 3 eq o = %d (%t)\n", uint8(xor.ByteArray(x1,x2)[1] % 3), uint8(xor.ByteArray(x1,x2)[1] % 3) == c.key.MigrationCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil;
|
||||||
|
}
|
Loading…
Reference in New Issue