[lib.keyset] created basic 'keyset' with {secret, depth, mindepth, maxdepth, consumption} ; METHODS{ 'Create(min,max)', 'Hash', 'Decrement', 'Write(Writer)', 'Read(Reader)' }
This commit is contained in:
parent
1bb7ede29a
commit
6d0a99b0d6
|
@ -0,0 +1,212 @@
|
||||||
|
package keyset
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"git.xdrm.io/schastsp/lib/scha"
|
||||||
|
"math/rand"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const a = 12
|
||||||
|
|
||||||
|
/* Attributes */
|
||||||
|
type Set struct {
|
||||||
|
min uint16 // min depth
|
||||||
|
depth uint16 // cur depth
|
||||||
|
max uint16 // max depth
|
||||||
|
|
||||||
|
sec []byte // secret
|
||||||
|
consumption uint // consumption level
|
||||||
|
// 0: none
|
||||||
|
// 1: need to migrate
|
||||||
|
// 2: waiting migration
|
||||||
|
// 3: validated migration
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (1) Creates a new KeySet
|
||||||
|
*
|
||||||
|
* @min<uint16> Minimum depth value
|
||||||
|
* @max<uint16> Maximum depth value
|
||||||
|
*
|
||||||
|
* @return outName<outType> outDesc
|
||||||
|
*
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
func Create(min uint16, max uint16) (*Set, error) {
|
||||||
|
|
||||||
|
/* (1) Fail if min >= max */
|
||||||
|
if min >= max {
|
||||||
|
return nil, errors.New("Max depth is not greater than Min depth")
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (2) Instanciate */
|
||||||
|
var instance = new(Set)
|
||||||
|
|
||||||
|
/* (3) Set attributes */
|
||||||
|
instance.min = min
|
||||||
|
instance.max = max
|
||||||
|
|
||||||
|
/* (4) Generate values if <nil> secret */
|
||||||
|
if instance.sec == nil {
|
||||||
|
instance.generate()
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (2) Generates a pseudo-random KeySet
|
||||||
|
*
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
func (s *Set) generate() {
|
||||||
|
|
||||||
|
/* (1) Seed randomness */
|
||||||
|
rand.Seed(time.Now().UTC().UnixNano())
|
||||||
|
|
||||||
|
/* (1) Generate new secret
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
/* (1) Reset current secret */
|
||||||
|
s.sec = make([]byte, scha.HSIZE)
|
||||||
|
|
||||||
|
/* (2) Generate each char. until same length as hash digest */
|
||||||
|
for i := uint16(0); i < scha.HSIZE; i++ {
|
||||||
|
s.sec[i] = byte(rand.Int() % 256)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (2) Manage other attributes
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
/* (1) Random depth pick init */
|
||||||
|
var randMin, randMax uint16 = s.min + (s.max-s.min)/2, s.max
|
||||||
|
|
||||||
|
/* (2) Select "random" depth */
|
||||||
|
s.depth = randMin + uint16(rand.Intn(int(randMax-randMin)))
|
||||||
|
|
||||||
|
/* (3) Reset comsumption level */
|
||||||
|
s.consumption = 0
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (3) Get current hash
|
||||||
|
*
|
||||||
|
* @return digest<[]byte]> Current hash representing the set
|
||||||
|
*
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
func (s Set) Hash() ([]byte, error) {
|
||||||
|
|
||||||
|
/* (1) Get digest */
|
||||||
|
digest, err := scha.Hash(s.sec, uint(s.depth), nil, nil)
|
||||||
|
|
||||||
|
/* (2) Dispatch error */
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (3) Else -> return digest */
|
||||||
|
return digest, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (4) Decrement depth
|
||||||
|
*
|
||||||
|
* @return remaining<uint> Remaining hashes before migration
|
||||||
|
*
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
func (s *Set) Decrement() uint16 {
|
||||||
|
|
||||||
|
/* (1) Decrement the depth */
|
||||||
|
s.depth--
|
||||||
|
|
||||||
|
/* (2) If near minDepth (10 far): set consumption to 1 */
|
||||||
|
if s.depth <= s.min+10 {
|
||||||
|
s.consumption = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (3) Return remaining attempts */
|
||||||
|
return s.depth - s.max
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (5) Serialisation
|
||||||
|
*
|
||||||
|
* @return serial<string> String representation
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* === FORMAT ===
|
||||||
|
*
|
||||||
|
* | hsize | secret | depth |
|
||||||
|
* +-----------+------------+---------+
|
||||||
|
* | 16 bits | hsize bits | 16 bits |
|
||||||
|
*
|
||||||
|
* == ENDIANNESS ==
|
||||||
|
*
|
||||||
|
* network endianness -> big-endian
|
||||||
|
*
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
func (s *Set) Write(writer io.Writer) error {
|
||||||
|
|
||||||
|
var err error;
|
||||||
|
|
||||||
|
/* (1) Copy hash size */
|
||||||
|
err = binary.Write(writer, binary.BigEndian, scha.HSIZE)
|
||||||
|
if err != nil { return err }
|
||||||
|
|
||||||
|
/* (2) Copy secret */
|
||||||
|
err = binary.Write(writer, binary.BigEndian, s.sec)
|
||||||
|
if err != nil { return err }
|
||||||
|
|
||||||
|
/* (3) Copy depth */
|
||||||
|
err = binary.Write(writer, binary.BigEndian, s.depth)
|
||||||
|
if err != nil { return err }
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (6) Builds a KeySet from its serial representation
|
||||||
|
*
|
||||||
|
* @serial<string> String representation
|
||||||
|
*
|
||||||
|
* @return instance<*Set> The corresponding set
|
||||||
|
* @return err<error> Optional error
|
||||||
|
*
|
||||||
|
* === FORMAT ===
|
||||||
|
*
|
||||||
|
* | hsize | secret | depth |
|
||||||
|
* +-----------+------------+---------+
|
||||||
|
* | 16 bits | hsize bits | 16 bits |
|
||||||
|
*
|
||||||
|
---------------------------------------------------------*/
|
||||||
|
func (s *Set) Read(reader io.Reader) error {
|
||||||
|
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
secretLength uint16
|
||||||
|
)
|
||||||
|
|
||||||
|
/* (1) Read the secret size */
|
||||||
|
err = binary.Read(reader, binary.BigEndian, &secretLength)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (2) Fail if secretLength different than digest size */
|
||||||
|
if secretLength != scha.HSIZE {
|
||||||
|
return errors.New("Invalid secret size (must be the same as digest size)")
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (3) Try to copy the secret */
|
||||||
|
err = binary.Read(reader, binary.BigEndian, &s.sec)
|
||||||
|
if err != nil { return err }
|
||||||
|
|
||||||
|
/* (4) Manage invalid secret size (mismatch secretLength) */
|
||||||
|
if uint16(len(s.sec)) != secretLength {
|
||||||
|
return errors.New("Mismatching secret size")
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (5) Try to copy the depth */
|
||||||
|
err = binary.Read(reader, binary.BigEndian, &s.depth)
|
||||||
|
if err != nil { return err }
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,124 @@
|
||||||
|
package keyset
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.xdrm.io/schastsp/lib/scha"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCreateNotMaxGreaterThanMin(t *testing.T) {
|
||||||
|
|
||||||
|
var _, err = Create(2, 1)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("Expected an error")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGenerationDepthBoundaries(t *testing.T) {
|
||||||
|
|
||||||
|
var min, max uint16 = 0x0f0, 0xfff
|
||||||
|
var rangeMin = min + (max-min)/2
|
||||||
|
var rangeMax = max
|
||||||
|
|
||||||
|
var created, err = Create(min, max)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Do not expected an error, got: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if created.depth < min || created.depth > max {
|
||||||
|
t.Errorf("Expected 'depth' to be in the range [%d, %d], got '%d'", rangeMin, rangeMax, created.depth)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSchaDecrementingProperty(t *testing.T) {
|
||||||
|
|
||||||
|
var h1, h2, hcheck []byte
|
||||||
|
var err error
|
||||||
|
var created *Set
|
||||||
|
|
||||||
|
created, err = Create(0x0f0, 0xfff)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Do not expected an error, got: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (1) Get current hash */
|
||||||
|
h1, err = created.Hash()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Do not expected an error, got: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (2) Decrement */
|
||||||
|
created.Decrement()
|
||||||
|
|
||||||
|
/* (3) Get new hash */
|
||||||
|
h2, err = created.Hash()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Do not expected an error, got: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (4) Try to guess h1 from h2 */
|
||||||
|
hcheck, err = scha.Hash(h2, 1, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Do not expected an error, got: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (5) Fail if property is not fulfilled */
|
||||||
|
for k, v := range h1 {
|
||||||
|
|
||||||
|
if v != hcheck[k] {
|
||||||
|
t.Errorf("Expected h(h[x-1]) to equel h[x]; expected '%x' ; got '%x'", h1, hcheck)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecrementMinimum(t *testing.T) {
|
||||||
|
|
||||||
|
var h1, h2, hcheck []byte
|
||||||
|
var err error
|
||||||
|
var created *Set
|
||||||
|
|
||||||
|
created, err = Create(0x0f0, 0xfff)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Do not expected an error, got: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (1) Get current hash */
|
||||||
|
h1, err = created.Hash()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Do not expected an error, got: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (2) Decrement */
|
||||||
|
created.Decrement()
|
||||||
|
|
||||||
|
/* (3) Get new hash */
|
||||||
|
h2, err = created.Hash()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Do not expected an error, got: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (4) Try to guess h1 from h2 */
|
||||||
|
hcheck, err = scha.Hash(h2, 1, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Do not expected an error, got: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (5) Fail if property is not fulfilled */
|
||||||
|
for k, v := range h1 {
|
||||||
|
|
||||||
|
if v != hcheck[k] {
|
||||||
|
t.Errorf("Expected h(h[x-1]) to equel h[x]; expected '%x' ; got '%x'", h1, hcheck)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue