From 35724cd3efc83feb04e1653db96f15d959f266a2 Mon Sep 17 00:00:00 2001 From: Norayr Chilingarian Date: Wed, 22 Jan 2014 00:50:20 +0400 Subject: [PATCH] ported TCrypt module Former-commit-id: 1736258d7de965f6206d1f7f82c93f3b3356321c --- makefile | 1 + makefile.gnuc.armv6j | 1 + makefile.gnuc.armv6j_hardfp | 1 + makefile.gnuc.armv7a_hardfp | 1 + makefile.gnuc.powerpc | 1 + makefile.gnuc.x86 | 1 + makefile.gnuc.x86_64 | 1 + src/lib/ulm/ulmTCrypt.Mod | 1762 +++++++++++++++++++++++++++++++++++ 8 files changed, 1769 insertions(+) create mode 100644 src/lib/ulm/ulmTCrypt.Mod diff --git a/makefile b/makefile index 4e3dc160..5972f55b 100644 --- a/makefile +++ b/makefile @@ -212,6 +212,7 @@ stage6: $(VOCSTATIC) -sP ulmAsymmetricCiphers.Mod $(VOCSTATIC) -sP ulmConclusions.Mod $(VOCSTATIC) -sP ulmRandomGenerators.Mod + $(VOCSTATIC) -sP ulmTCrypt.Mod #pow32 libs $(VOCSTATIC) -sP powStrings.Mod diff --git a/makefile.gnuc.armv6j b/makefile.gnuc.armv6j index d156db9c..9aad0938 100644 --- a/makefile.gnuc.armv6j +++ b/makefile.gnuc.armv6j @@ -211,6 +211,7 @@ stage6: $(VOCSTATIC) -sP ulmAsymmetricCiphers.Mod $(VOCSTATIC) -sP ulmConclusions.Mod $(VOCSTATIC) -sP ulmRandomGenerators.Mod + $(VOCSTATIC) -sP ulmTCrypt.Mod #pow32 libs $(VOCSTATIC) -sP powStrings.Mod diff --git a/makefile.gnuc.armv6j_hardfp b/makefile.gnuc.armv6j_hardfp index 85b10e3b..544be3ba 100644 --- a/makefile.gnuc.armv6j_hardfp +++ b/makefile.gnuc.armv6j_hardfp @@ -211,6 +211,7 @@ stage6: $(VOCSTATIC) -sP ulmAsymmetricCiphers.Mod $(VOCSTATIC) -sP ulmConclusions.Mod $(VOCSTATIC) -sP ulmRandomGenerators.Mod + $(VOCSTATIC) -sP ulmTCrypt.Mod #pow32 libs $(VOCSTATIC) -sP powStrings.Mod diff --git a/makefile.gnuc.armv7a_hardfp b/makefile.gnuc.armv7a_hardfp index c6fede7a..01b826dd 100644 --- a/makefile.gnuc.armv7a_hardfp +++ b/makefile.gnuc.armv7a_hardfp @@ -211,6 +211,7 @@ stage6: $(VOCSTATIC) -sP ulmAsymmetricCiphers.Mod $(VOCSTATIC) -sP ulmConclusions.Mod $(VOCSTATIC) -sP ulmRandomGenerators.Mod + $(VOCSTATIC) -sP ulmTCrypt.Mod #pow32 libs $(VOCSTATIC) -sP powStrings.Mod diff --git a/makefile.gnuc.powerpc b/makefile.gnuc.powerpc index 573b9f5e..7c4a54fe 100644 --- a/makefile.gnuc.powerpc +++ b/makefile.gnuc.powerpc @@ -211,6 +211,7 @@ stage6: $(VOCSTATIC) -sP ulmAsymmetricCiphers.Mod $(VOCSTATIC) -sP ulmConclusions.Mod $(VOCSTATIC) -sP ulmRandomGenerators.Mod + $(VOCSTATIC) -sP ulmTCrypt.Mod #pow32 libs $(VOCSTATIC) -sP powStrings.Mod diff --git a/makefile.gnuc.x86 b/makefile.gnuc.x86 index 637152b2..7451cf62 100644 --- a/makefile.gnuc.x86 +++ b/makefile.gnuc.x86 @@ -211,6 +211,7 @@ stage6: $(VOCSTATIC) -sP ulmAsymmetricCiphers.Mod $(VOCSTATIC) -sP ulmConclusions.Mod $(VOCSTATIC) -sP ulmRandomGenerators.Mod + $(VOCSTATIC) -sP ulmTCrypt.Mod #pow32 libs $(VOCSTATIC) -sP powStrings.Mod diff --git a/makefile.gnuc.x86_64 b/makefile.gnuc.x86_64 index 64a6b4e7..d9c597ae 100644 --- a/makefile.gnuc.x86_64 +++ b/makefile.gnuc.x86_64 @@ -211,6 +211,7 @@ stage6: $(VOCSTATIC) -sP ulmAsymmetricCiphers.Mod $(VOCSTATIC) -sP ulmConclusions.Mod $(VOCSTATIC) -sP ulmRandomGenerators.Mod + $(VOCSTATIC) -sP ulmTCrypt.Mod #pow32 libs $(VOCSTATIC) -sP powStrings.Mod diff --git a/src/lib/ulm/ulmTCrypt.Mod b/src/lib/ulm/ulmTCrypt.Mod new file mode 100644 index 00000000..e1909085 --- /dev/null +++ b/src/lib/ulm/ulmTCrypt.Mod @@ -0,0 +1,1762 @@ +(* Ulm's Oberon Library + Copyright (C) 1989-1997 by University of Ulm, SAI, D-89069 Ulm, Germany + ---------------------------------------------------------------------------- + Ulm's Oberon Library is free software; you can redistribute it + and/or modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either version + 2 of the License, or (at your option) any later version. + + Ulm's Oberon Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + ---------------------------------------------------------------------------- + E-mail contact: oberon@mathematik.uni-ulm.de + ---------------------------------------------------------------------------- + $Id: TCrypt.om,v 1.1 1997/04/02 11:54:02 borchert Exp borchert $ + ---------------------------------------------------------------------------- + $Log: TCrypt.om,v $ + Revision 1.1 1997/04/02 11:54:02 borchert + Initial revision + + ---------------------------------------------------------------------------- +*) + +MODULE ulmTCrypt; (* Michael Szczuka *) + + (* Trautner's association method for key exchange *) + + IMPORT AsymmetricCiphers := ulmAsymmetricCiphers, BlockCiphers := ulmBlockCiphers, Ciphers := ulmCiphers, Conclusions := ulmConclusions, Events := ulmEvents, + NetIO := ulmNetIO, PersistentObjects := ulmPersistentObjects, Random := ulmRandomGenerators, RelatedEvents := ulmRelatedEvents, + Services := ulmServices, Streams := ulmStreams, SYS := SYSTEM; + + CONST + M = 16; (* size of an element of CC(M) [ring of Circular Convolution] *) + MaxVar = 8; (* number of variables of a polynomial *) + MaxNrExp = 4; (* maxiumum number of different exponts used during + initialisaton *) + Dim = 2; (* dimension of the linear recursion *) + Rounds = 16; (* length of the linear recursion in rounds *) + LastRounds = 4; (* use the last LastRounds polynomial vectors as + the composed function eta *) + reg = 1; sing = 2; random = 3; + LIST = TRUE; NOLIST = FALSE; + MaxTerms = 1000; + + CONST + writeSetFailed = 0; + readSetFailed = 1; + notRegular = 2; + errorcodes = 3; + + TYPE + (* an element out of CC(M) *) + CCMElement = SET; + Exponent = ARRAY MaxVar OF SHORTINT; + + TYPE + (* a polynomial with coefficients out of CC(M) *) + Polynom = POINTER TO PolynomRec; + PolynomRec = RECORD + koeff : CCMElement; + exp : Exponent; + next : Polynom; + END; + + TYPE + VektorCCM = ARRAY Dim OF CCMElement; + VektorPolynom = ARRAY Dim OF Polynom; + MatCCM = ARRAY Dim, Dim OF CCMElement; + MatPolynom = ARRAY Dim, Dim OF Polynom; + ListCCM = ARRAY Rounds OF CCMElement; + ListPolynom = ARRAY Rounds OF Polynom; + ChainCCM = ARRAY Rounds OF VektorCCM; + ChainPolynom = ARRAY Rounds OF VektorPolynom; + (* to increase the performance of the algorithm there shouldn't be too + many different exponents to start with *) + ListExp = ARRAY MaxNrExp OF Exponent; + + TYPE + (* this type is the input of the TCrypt method *) + TCryptInput = POINTER TO TCryptInputRec; + TCryptInputRec = RECORD + arg : ARRAY MaxVar OF CCMElement; + END; + + TYPE + (* result type after encryption with the public key *) + TCryptTmp = POINTER TO TCryptTmpRec; + TCryptTmpRec = RECORD + numerator : ChainCCM; + denominator : ListCCM; + END; + + TYPE + (* result type of the algorithm *) + TCryptRes = POINTER TO TCryptResRec; + TCryptResRec = RECORD + arg : ARRAY LastRounds OF VektorCCM; + END; + + TYPE + (* this type represents the public function f resp. phi *) + Phi = POINTER TO PhiRec; + PhiRec = RECORD + num : ChainPolynom; + denom : ListPolynom; + END; + + TYPE + (* the private/secret function g resp. psi consisting of an inital matrix + and a permutation *) + Psi = POINTER TO PsiRec; + PsiRec = RECORD + (* although the inital matrix consists only of elements out of CC(M) + this generalization is useful since all other matrces consist of + polynomials *) + initialmatrix : MatCCM; + (* correcting factors *) + korrNum : ChainCCM; + korrDenom : ListCCM; + END; + + (* the public function h resp. eta being the composition of f/phi + and g/psi *) + TYPE + Eta = POINTER TO EtaRec; + EtaRec = RECORD + p : ARRAY LastRounds OF VektorPolynom; + END; + + TYPE + (* the declaration of a basic type which PublicCipher and PrivateCipher + are descendents from seems a good idea ... at least to me :) *) + Cipher* = POINTER TO CipherRec; + CipherRec* = RECORD (AsymmetricCiphers.CipherRec) END; + (* the specific format of a public key for Trautner's technique *) + PublicCipher = POINTER TO PublicCipherRec; + PublicCipherRec = RECORD + (CipherRec) + phi : Phi; + eta : Eta; + END; + (* the specific format of a key for Trautner's technique *) + PrivateCipher = POINTER TO PrivateCipherRec; + PrivateCipherRec = RECORD + (CipherRec) + phi : Phi; + psi : Psi; + eta : Eta; + END; + + TYPE + ErrorEvent = POINTER TO ErrorEventRec; + ErrorEventRec = RECORD + (Events.EventRec) + errorcode : SHORTINT; + END; + + VAR + pubType, privType, cipherType : Services.Type; + pubIf, privIf, cipherIf : PersistentObjects.Interface; + NullCCM, EinsCCM : CCMElement; (* the zero and unit of CC(M) *) + NullExp : Exponent; (* consists of zero exponents *) + NullExpList : ListExp; (* a pseudo list for CreatePolynom *) + GlobalExpList : ListExp; (* contains the exponents which should be used + when calling CreatePolynom *) + NullPolynom : Polynom; (* the zero polynomial *) + PolFeld : ARRAY MaxTerms OF Polynom; (* used for sorting purposes *) + PreEvalArg : ARRAY M OF TCryptInput; (* precomputed values to speed + up evaluation of a polynomial *) + k : SHORTINT; (* simple counter during initialisation *) + error : Events.EventType; + errormsg : ARRAY errorcodes OF Events.Message; + + + (* ***** error handling ***** *) + + PROCEDURE InitErrorHandling; + BEGIN + Events.Define(error); + errormsg[writeSetFailed] := "couldn't write set"; + errormsg[readSetFailed] := "couldn't read set"; + errormsg[notRegular] := "element isn't regular"; + END InitErrorHandling; + + PROCEDURE Error(s: Streams.Stream; errorcode: SHORTINT); + VAR + event: ErrorEvent; + BEGIN + NEW(event); + event.message := errormsg[errorcode]; + event.type := error; + event.errorcode := errorcode; + RelatedEvents.Raise(s, event); + END Error; + + (* ***** arithmetic functions for elements out of CC(M) ***** *) + + PROCEDURE RegulaerCCM (x: CCMElement) : BOOLEAN; + (* tests x for regularity [a regular CCMElement contains an odd number of + set bits]; returns TRUE when x is regular, FALSE otherwise *) + VAR + res, i : SHORTINT; + BEGIN + i := 0; + res := 0; + REPEAT (* counting the set bits *) + IF i IN x THEN + INC(res); + END; + INC(i); + UNTIL i>=M; + RETURN ((res MOD 2) = 1); + END RegulaerCCM; + + PROCEDURE EqualCCM (x, y: CCMElement) : BOOLEAN; + (* compares x and y for equality; if x and y are equal TRUE is returned, + FALSE otherwise *) + VAR + i : SHORTINT; + BEGIN + i := 0; + WHILE i < M DO + IF ((i IN x) & (~(i IN y))) OR ((~(i IN x)) & (i IN y)) THEN + RETURN FALSE; + END; + INC(i); + END; + RETURN TRUE; + END EqualCCM; + + PROCEDURE AddCCM (x, y: CCMElement; VAR z: CCMElement); + (* add x and y in CC(M) *) + VAR + i : SHORTINT; + BEGIN + z := NullCCM; + i := 0; + REPEAT + IF ((i IN x) & (~(i IN y))) OR ((~(i IN x)) & (i IN y)) THEN + z := z + {i}; + END; + INC(i); + UNTIL i>=M; + END AddCCM; + + PROCEDURE MulCCM (x, y: CCMElement; VAR z: CCMElement); + (* multiply x and y in CC(M) *) + VAR + i, j, diff : SHORTINT; + tmp : INTEGER; + BEGIN + z := NullCCM; + i := 0; + REPEAT + j := 0; + tmp := 0; + REPEAT + diff := i-j; + IF diff >= 0 THEN + IF (j IN x) & (diff IN y) THEN + INC(tmp); + END; + ELSE + IF (j IN x) & ((M+diff) IN y) THEN + INC(tmp); + END; + END; + INC(j); + UNTIL j>=M; + IF (tmp MOD 2) = 1 THEN + z := z + {i}; + END; + INC(i); + UNTIL i>=M; + END MulCCM; + + PROCEDURE PowerCCM (x: CCMElement; exp: INTEGER; VAR z: CCMElement); + (* raises x to the power exp in CC(M) *) + VAR + tmp : CCMElement; + BEGIN + (* some special cases first *) + IF exp >= M THEN + IF ~RegulaerCCM(x) THEN + (* x is singular -> result is zero *) + z := NullCCM; + RETURN; + END; + (* x is regular -> compute the modulus of exp mod M and use this + instead of exp *) + exp := exp MOD M; + END; + IF exp = 0 THEN + z := EinsCCM; + RETURN; + END; + IF exp = 1 THEN + z := x; + RETURN; + END; + + (* default case; use a "square and multiply" technique *) + tmp := x; + z := EinsCCM; + REPEAT + IF exp MOD 2 = 1 THEN + MulCCM(z, tmp, z); + END; + exp := exp DIV 2; + MulCCM(tmp, tmp, tmp); + UNTIL exp < 1; + END PowerCCM; + + PROCEDURE CreateCCM (VAR x: CCMElement; mode: SHORTINT); + (* creates a random element out of CC(M) depending on mode which + can be reg, sing or random; + the result is in any case different from the zero *) + VAR + i, SetBits: SHORTINT; + BEGIN + x := NullCCM; + REPEAT + i := 0; + SetBits := 0; + REPEAT + IF Random.Flip() THEN + (* set bit *) + x := x + {i}; + INC(SetBits); + END; + INC(i); + UNTIL i >= (M-1); + UNTIL SetBits > 0; (* at least one bit must be set so that the result + differs from zero *) + + CASE mode OF + random: + IF Random.Flip() THEN + x := x + {M-1}; + END; + | sing: (* singular element - even # of bits *) + IF (SetBits MOD 2) = 1 THEN + x := x + {M-1}; + END; + | reg: (* regular element - odd # of bits *) + IF ((SetBits + 1) MOD 2) = 1 THEN + x := x + {M-1}; + END; + END; + END CreateCCM; + + (* ***** arithmetic functions for polynomials over CC(M) ***** *) + + PROCEDURE LengthPolynom(p: Polynom) : INTEGER; + (* returns the number of terms which make up the polynomial p *) + VAR + i : INTEGER; + BEGIN + i := 0; + WHILE p # NIL DO + INC(i); + p := p.next; + END; + RETURN i; + END LengthPolynom; + + PROCEDURE RegulaerPolynom (p: Polynom) : BOOLEAN; + (* tests the regularity of a polynomial [a polynomial is regular + iff the # of regular coefficients is odd] *) + VAR + regkoeffs : SHORTINT; + BEGIN + regkoeffs := 0; + WHILE p # NIL DO + IF RegulaerCCM(p.koeff) THEN + (* count # of reg. coefficients *) + INC(regkoeffs); + END; + p := p.next; + END; + RETURN (regkoeffs MOD 2) = 1; + END RegulaerPolynom; + + PROCEDURE CmpExp (exp1, exp2: Exponent) : SHORTINT; + (* compares two exponent vectors and returns 0 on equality, a + positive value if exp1>exp2 and a negative value if exp1 e2 THEN + cmp := 1; diff := TRUE; + END; + END; + INC(i); + UNTIL i >= MaxVar; + + IF sum1 < sum2 THEN + RETURN -2; + END; + IF sum1 > sum2 THEN + RETURN 2; + END; + + RETURN cmp + END CmpExp; + + PROCEDURE ArrangePolynom (VAR p: Polynom); + (* arrange a polynomial according to the order given by CmpExp *) + VAR + r : Polynom; + cnt : INTEGER; + + PROCEDURE SortPolynom(left, right: INTEGER); + (* sort the global field PolFeld with the quicksort algorithm *) + VAR + mid : INTEGER; + + PROCEDURE Partition(l, r: INTEGER) : INTEGER; + VAR + koeff : CCMElement; + exp : Exponent; + cmp : Exponent; + i, j : INTEGER; + BEGIN + cmp := PolFeld[(l+r) DIV 2].exp; + i := l-1; + j := r+1; + LOOP + REPEAT + DEC(j); + UNTIL CmpExp(PolFeld[j].exp, cmp) >= 0; + REPEAT + INC(i); + UNTIL CmpExp(PolFeld[i].exp, cmp) <= 0; + IF i < j THEN + koeff := PolFeld[i].koeff; + exp := PolFeld[i].exp; + PolFeld[i].koeff := PolFeld[j].koeff; + PolFeld[i].exp := PolFeld[j].exp; + PolFeld[j].koeff := koeff; + PolFeld[j].exp := exp; + ELSE + RETURN j; + END; + END; + END Partition; + + BEGIN + IF left < right THEN + mid := Partition(left, right); + SortPolynom(left, mid); + SortPolynom(mid+1, right); + END; + END SortPolynom; + + BEGIN (* ArrangePolynom *) + IF p = NIL THEN + RETURN; + END; + r := p; + cnt := 0; + WHILE (p # NIL) & (cnt < MaxTerms) DO + PolFeld[cnt] := p; + INC(cnt); + p := p.next; + END; + (* polynomial contains too many terms; this shouldn't happen if all + parameters are set to reasonable values and MaxTerms is high + enough *) + ASSERT(cnt 1 THEN + SortPolynom(0, cnt-1); + END; + p := r; + END ArrangePolynom; + + PROCEDURE CopyPolynom (s: Polynom; VAR t: Polynom); + (* copy the source polynomial s to a new target t *) + VAR + troot : Polynom; + BEGIN + IF s = NIL THEN + t := NIL; + RETURN; + END; + NEW(t); + troot := t; (* save the root of t *) + WHILE s # NIL DO + troot.koeff := s.koeff; + troot.exp := s.exp; + s := s.next; + IF s # NIL THEN + NEW(troot.next); + troot := troot.next; + ELSE + troot.next := NIL; + END; + END; + END CopyPolynom; + + PROCEDURE AddPolynom (p, q: Polynom; VAR r: Polynom); + (* add two polynomial; the polynomials must be sorted by the exponents as + is the result *) + VAR + term1, term2 : Polynom; + last : Polynom; (* the last term of the result *) + tmp : Polynom; + cmpres : SHORTINT; + BEGIN + IF (p = NIL) & (q = NIL) THEN + r := NIL; + RETURN; + END; + NEW(r); + term1 := p; (* term1 runs through all terms of p *) + term2 := q; (* same with term2 for q *) + tmp := r; (* save the root of r *) + last := tmp; + REPEAT + IF (term1 = NIL) OR (term2 = NIL) THEN + IF term2 = NIL THEN + (* no further terms in q *) + WHILE term1 # NIL DO + (* copy the remaining terms of p *) + tmp.koeff := term1.koeff; + tmp.exp := term1.exp; + term1 := term1.next; + IF ~EqualCCM(tmp.koeff, NullCCM) THEN + last := tmp; + NEW(tmp.next); + tmp := tmp.next; + END; + END; + ELSE (* no further terms in p *) + WHILE term2 # NIL DO + tmp.koeff := term2.koeff; + tmp.exp := term2.exp; + term2 := term2.next; + IF ~EqualCCM(tmp.koeff, NullCCM) THEN + last := tmp; + NEW(tmp.next); + tmp := tmp.next; + END; + END; + END; + ELSE (* both p and q still have a term *) + cmpres := CmpExp(term1.exp, term2.exp); + IF cmpres = 0 THEN (* add when exponents are equal *) + AddCCM(term1.koeff, term2.koeff, tmp.koeff); + tmp.exp := term1.exp; + term1 := term1.next; + term2 := term2.next; + ELSE + IF cmpres < 0 THEN (* exp2 > exp1 *) + tmp.koeff := term2.koeff; + tmp.exp := term2.exp; + term2 := term2.next; + ELSE (* exp1 > exp2 *) + tmp.koeff := term1.koeff; + tmp.exp := term1.exp; + term1 := term1.next; + END; + END; + (* zero coefficients = zero terms shouldn't occur in the result *) + IF ~EqualCCM(tmp.koeff, NullCCM) THEN + NEW(tmp.next); + last := tmp; + tmp := tmp.next; + END; + END; + UNTIL (term1 = NIL) & (term2 = NIL); + + (* forget last created term *) + last.next := NIL; + END AddPolynom; + + PROCEDURE MulTerm (p, term: Polynom; VAR r: Polynom); + (* multiply a polynomial with a single term; is used by MulPolynom *) + VAR + tmp : Polynom; + last : Polynom; + + (* add two exponent vetors; addition is modulo M *) + PROCEDURE AddExp (exp1, exp2 : Exponent; VAR res: Exponent); + VAR + i : SHORTINT; + BEGIN + i := 0; + WHILE i 0 DO + IF (exp MOD 2) = 1 THEN + MulPolynom(res, tmp, res); + END; + MulPolynom(tmp, tmp, tmp); + exp := exp DIV 2; + END; + END InvertPolynom; + + PROCEDURE EvalPolynom (p: Polynom; VAR res: CCMElement); + (* evaluate p; a precomputed list of all the powers of the argument can + be found in the global variable PreEvalArg *) + VAR + i : SHORTINT; + pow, prod : CCMElement; + BEGIN + res := NullCCM; + IF p = NIL THEN + RETURN; + END; + WHILE p # NIL DO + prod := PreEvalArg[p.exp[0]].arg[0]; + i := 1; + REPEAT + pow := PreEvalArg[p.exp[i]].arg[i]; + MulCCM(prod, pow, prod); + INC(i); + UNTIL i >= MaxVar; + MulCCM(prod, p.koeff, prod); + AddCCM(res, prod, res); + p := p.next; + END; + END EvalPolynom; + + PROCEDURE CreateExp (VAR exp: Exponent); + (* creates a random vector of exponents *) + VAR + i : SHORTINT; + BEGIN + i := 0; + WHILE i 0 DO + IF (kk MOD 2) = 1 THEN + MulCCM(tmp, PreEvalArg[ii].arg[i], tmp); + END; + INC(ii,ii); + kk := kk DIV 2; + END; + PreEvalArg[k].arg[i] := tmp; + INC(k); + END; + INC(i); + END; + END PreComputeArgs; + + PROCEDURE EvaluatePhi (arg: TCryptInput; data: Phi) : TCryptTmp; + (* evaluate the public function phi (represented by data) with + argument arg *) + VAR + res : TCryptTmp; + r, d : SHORTINT; + BEGIN + NEW(res); + PreComputeArgs(arg); + r := 0; + WHILE r < Rounds DO + d := 0; + WHILE d < Dim DO + EvalPolynom(data.num[r][d], res.numerator[r][d]); + INC(d); + END; + EvalPolynom(data.denom[r], res.denominator[r]); + INC(r); + END; + RETURN res; + END EvaluatePhi; + + PROCEDURE EvaluatePsi (arg: TCryptTmp; data: Psi) : TCryptRes; + (* evalute the private function psi *) + VAR + res : TCryptRes; + mat, prev : MatCCM; + num, denom, inv : CCMElement; + vek : VektorCCM; + A : ChainCCM; + r, d : SHORTINT; + BEGIN + (* first correct the input with the correlating inverts *) + MulCCM(arg.denominator[0], data.korrDenom[0], denom); + PowerCCM(denom, M-1, inv); + MulCCM(arg.numerator[0][0], data.korrNum[0][0], num); + MulCCM(num, inv, vek[0]); + MulCCM(arg.numerator[0][1], data.korrNum[0][1], num); + MulCCM(num, inv, vek[1]); + MulMatrix(data.initialmatrix, vek, A[0]); + prev := data.initialmatrix; + r := 1; + WHILE r < Rounds DO + (* the matrix for the current round of the recursion must be computed + each round *) + BuildMatrix(mat, prev, A[r-1]); + prev := mat; + MulCCM(arg.denominator[r], data.korrDenom[r], denom); + PowerCCM(denom, M-1, inv); + MulCCM(arg.numerator[r][0], data.korrNum[r][0], num); + MulCCM(num, inv, vek[0]); + MulCCM(arg.numerator[r][1], data.korrNum[r][1], num); + MulCCM(num, inv, vek[1]); + MulMatrix(mat, vek, A[r]); + INC(r); + END; + NEW(res); + r := 0; + WHILE r < LastRounds DO + d := 0; + WHILE d < Dim DO + res.arg[r][d] := A[Rounds-LastRounds+r][d]; + INC(d); + END; + INC(r); + END; + RETURN res; + END EvaluatePsi; + + PROCEDURE EvaluateEta (arg: TCryptInput; data: Eta) : TCryptRes; + (* evaluate the public function eta (composition of phi and psi) *) + VAR + l, d : SHORTINT; + res : TCryptRes; + BEGIN + NEW(res); + PreComputeArgs(arg); + l := 0; + WHILE l < LastRounds DO + d := 0; + WHILE d < Dim DO + EvalPolynom(data.p[l][d], res.arg[l][d]); + INC(d); + END; + INC(l); + END; + RETURN res; + END EvaluateEta; + + PROCEDURE Eof (s: Streams.Stream) : BOOLEAN; + (* returns TRUE if no bytes are left to read from stream s *) + VAR + b : SYS.BYTE; + BEGIN + RETURN ~Streams.ReadByte(s, b) OR ~Streams.Back(s); + END Eof; + + PROCEDURE Encrypt (msg: Streams.Stream; key: Ciphers.Cipher; + length: INTEGER; s: Streams.Stream) : BOOLEAN; + (* interface procedure for Ciphers.Encrypt *) + VAR + i, j : SHORTINT; + ccmarg : TCryptInput; + ccmres : TCryptTmp; + wholeStream : BOOLEAN; + BEGIN + (* check if the whole stream msg shall be encrypted or only a certain + amount of bytes *) + IF length <= 0 THEN + wholeStream := TRUE; + ELSE + wholeStream := FALSE + END; + NEW(ccmarg); + WHILE ~Eof(msg) & (wholeStream OR (length > 0)) DO + i := 0; + WHILE i < MaxVar DO + IF ~NetIO.ReadSet(msg, ccmarg.arg[i]) THEN + Error(msg, readSetFailed); + RETURN FALSE; + END; + IF ~RegulaerCCM(ccmarg.arg[i]) THEN + Error(msg, notRegular); + RETURN FALSE; + END; + INC(i); + END; + IF key IS PublicCipher THEN + ccmres := EvaluatePhi(ccmarg, key(PublicCipher).phi); + ELSE + ccmres := EvaluatePhi(ccmarg, key(PrivateCipher).phi); + END; + i := 0; + WHILE i < Rounds DO + j := 0; + WHILE j < Dim DO + IF ~NetIO.WriteSet(s, ccmres.numerator[i][j]) THEN + Error(s, writeSetFailed); + RETURN FALSE; + END; + INC(j); + END; + IF ~NetIO.WriteSet(s, ccmres.denominator[i]) THEN + Error(s, writeSetFailed); + RETURN FALSE; + END; + INC(i); + END; + DEC(length, MaxVar*(M DIV 8)); + END; + RETURN TRUE; + END Encrypt; + + PROCEDURE Decrypt (msg: Streams.Stream; key: Ciphers.Cipher; + length: INTEGER; s: Streams.Stream) : BOOLEAN; + (* interface procedure for Ciphers.Decrypt *) + VAR + i, j : SHORTINT; + inNum, inDenom, out : ARRAY (M DIV 8) OF SYS.BYTE; + ccmarg : TCryptTmp; + ccmres : TCryptRes; + wholeStream : BOOLEAN; + BEGIN + IF length < 0 THEN + wholeStream := TRUE; + ELSE + wholeStream := FALSE; + END; + WITH key:PrivateCipher DO + NEW(ccmarg); + WHILE ~Eof(msg) & (wholeStream OR (length > 0)) DO + i := 0; + WHILE i < Rounds DO + j := 0; + WHILE j < Dim DO + IF ~NetIO.ReadSet(msg, ccmarg.numerator[i][j]) THEN + Error(msg, readSetFailed); + RETURN FALSE; + END; + INC(j); + END; + IF ~NetIO.ReadSet(msg, ccmarg.denominator[i]) THEN + Error(msg, readSetFailed); + RETURN FALSE; + END; + INC(i); + END; + ccmres := EvaluatePsi(ccmarg, key.psi); + i := 0; + WHILE i < LastRounds DO + j := 0; + WHILE j < Dim DO + IF ~NetIO.WriteSet(s, ccmres.arg[i][j]) THEN + Error(s, writeSetFailed); + RETURN FALSE; + END; + INC(j); + END; + INC(i); + END; + DEC (length, Rounds*Dim*(M DIV 8)); + END; + END; + RETURN TRUE; + END Decrypt; + + PROCEDURE ComposedEncrypt (msg: Streams.Stream; key: Ciphers.Cipher; + length: INTEGER; s: Streams.Stream) : BOOLEAN; + (* interface procedure for AsymmetricCiphers.ComposedEncrypt *) + VAR + i, j : SHORTINT; + ccmarg : TCryptInput; + ccmres : TCryptRes; + in, out : ARRAY (M DIV 8) OF SYS.BYTE; + wholeStream : BOOLEAN; + BEGIN + IF length < 0 THEN + wholeStream := TRUE; + ELSE + wholeStream := FALSE; + END; + NEW(ccmarg); + WHILE ~Eof(msg) & (wholeStream OR (length > 0)) DO + i := 0; + WHILE i < MaxVar DO + IF ~NetIO.ReadSet(msg, ccmarg.arg[i]) THEN + Error(msg, readSetFailed); + RETURN FALSE; + END; + INC(i); + END; + IF key IS PublicCipher THEN + ccmres := EvaluateEta(ccmarg, key(PublicCipher).eta); + ELSE + ccmres := EvaluateEta(ccmarg, key(PrivateCipher).eta); + END; + i := 0; + WHILE i < LastRounds DO + j := 0; + WHILE j < Dim DO + IF ~NetIO.WriteSet(s, ccmres.arg[i][j]) THEN + Error(s, writeSetFailed); + RETURN FALSE; + END; + INC(j); + END; + INC(i); + END; + DEC (length, MaxVar*(M DIV 8)); + END; + RETURN TRUE; + END ComposedEncrypt; + + PROCEDURE RandomStream (s: Streams.Stream); + (* writes some random elements of CC(M) to the stream s which can then + be used as an input for Trautner's TCRYPT *) + VAR + ccm : CCMElement; + bytes : ARRAY M DIV 8 OF SYS.BYTE; + i : INTEGER; + BEGIN + i := 0; + WHILE i < MaxVar DO + CreateCCM(ccm, reg); + IF ~NetIO.WriteSet(s, ccm) THEN + Error(s, writeSetFailed); + END; + INC(i); + END; + END RandomStream; + + PROCEDURE PublicCipherCreate (VAR obj: PersistentObjects.Object); + (* constructor for a public cipher *) + VAR + pub : PublicCipher; + if : AsymmetricCiphers.Interface; + caps : AsymmetricCiphers.CapabilitySet; + BEGIN + NEW(pub); NEW(pub.phi); NEW(pub.eta); + PersistentObjects.Init(pub, pubType); + NEW(if); if.encrypt := Encrypt; if.decrypt := NIL; + if.compencrypt := ComposedEncrypt; if.split := NIL; + if.randomStream := RandomStream; + caps := {AsymmetricCiphers.composed}; + AsymmetricCiphers.Init(pub, if, caps, M*MaxVar, M*Dim); + obj := pub; + END PublicCipherCreate; + + PROCEDURE Split (VAR public: AsymmetricCiphers.Cipher; + key: AsymmetricCiphers.Cipher); + (* interface procedure for asymmetric interface *) + VAR + pub: PublicCipher; + BEGIN + WITH key:PrivateCipher DO + PublicCipherCreate(SYS.VAL(PersistentObjects.Object, pub)); + pub.phi := key.phi; + pub.eta := key.eta; + public := pub; + END; + END Split; + + PROCEDURE CipherCreate (VAR obj: PersistentObjects.Object); + (* constructor for a private cipher *) + VAR + key : PrivateCipher; + if : AsymmetricCiphers.Interface; + caps : AsymmetricCiphers.CapabilitySet; + BEGIN + NEW(key); NEW(key.phi); NEW(key.psi); NEW(key.eta); + PersistentObjects.Init(key, privType); + NEW(if); if.encrypt := Encrypt; if.decrypt := Decrypt; + if.compencrypt := ComposedEncrypt; if.split := Split; + if.randomStream := RandomStream; + caps := {AsymmetricCiphers.composed, AsymmetricCiphers.isPrivateKey}; + AsymmetricCiphers.Init(key, if, caps, M*MaxVar, M*Dim); + obj := key; + END CipherCreate; + + PROCEDURE Create* (VAR key: Ciphers.Cipher); + (* creates a cipher for the use with Trautner's TCRYPT algorithm *) + VAR + tmpKey : PrivateCipher; + phi : Phi; + psi : Psi; + eta : Eta; + BEGIN + CipherCreate(SYS.VAL(PersistentObjects.Object, tmpKey)); + CreateMaps(tmpKey.phi, tmpKey.psi, tmpKey.eta); + key := tmpKey; + END Create; + + PROCEDURE WritePolynom (s: Streams.Stream; p: Polynom) : BOOLEAN; + (* writes the polynomial p onto the stream s *) + CONST + index = M DIV 8; + VAR + nrOfTerms, i : INTEGER; + bytes : ARRAY index OF SYS.BYTE; + BEGIN + nrOfTerms := LengthPolynom(p); + IF ~NetIO.WriteInteger(s, nrOfTerms) THEN + RETURN FALSE; + END; + WHILE nrOfTerms > 0 DO + IF ~NetIO.WriteSet(s, p.koeff) THEN + RETURN FALSE; + END; + i := 0; + WHILE i < MaxVar DO + IF ~NetIO.WriteShortInt(s, p.exp[i]) THEN + RETURN FALSE; + END; + INC(i); + END; + p := p.next; + DEC(nrOfTerms); + END; + RETURN TRUE; + END WritePolynom; + + PROCEDURE ReadPolynom (s: Streams.Stream; VAR p: Polynom) : BOOLEAN; + (* reads a polynomial from stream s *) + CONST + index = M DIV 8; + VAR + nrOfTerms, i : INTEGER; + pol : Polynom; + bytes : ARRAY index OF SYS.BYTE; + BEGIN + IF ~NetIO.ReadInteger(s, nrOfTerms) THEN + RETURN FALSE; + END; + NEW(p); + pol := p; + WHILE nrOfTerms > 0 DO + IF ~NetIO.ReadSet(s, pol.koeff) THEN + RETURN FALSE; + END; + i := 0; + WHILE i < MaxVar DO + IF ~NetIO.ReadShortInt(s, pol.exp[i]) THEN + RETURN FALSE; + END; + INC(i); + END; + DEC(nrOfTerms); + IF nrOfTerms > 0 THEN + NEW(pol.next); + pol := pol.next; + END + END; + RETURN TRUE; + END ReadPolynom; + + PROCEDURE PhiWrite (s: Streams.Stream; data: Phi) : BOOLEAN; + (* writes the data structure for the public function phi onto a stream *) + VAR + r, d, k : INTEGER; + BEGIN + r := 0; + WHILE r < Rounds DO + d := 0; + WHILE d < Dim DO + IF ~WritePolynom(s, data.num[r][d]) THEN + RETURN FALSE; + END; + INC(d); + END; + IF ~WritePolynom(s, data.denom[r]) THEN + RETURN FALSE; + END; + INC(r); + END; + RETURN TRUE; + END PhiWrite; + + PROCEDURE PhiRead (s: Streams.Stream; VAR data: Phi) : BOOLEAN; + (* reads the data structure for the public function phi from a stream *) + VAR + r, d, k : INTEGER; + BEGIN + NEW(data); + r := 0; + WHILE r < Rounds DO + d := 0; + WHILE d < Dim DO + IF ~ReadPolynom(s, data.num[r][d]) THEN + RETURN FALSE; + END; + INC(d); + END; + IF ~ReadPolynom(s, data.denom[r]) THEN + RETURN FALSE; + END; + INC(r); + END; + RETURN TRUE; + END PhiRead; + + PROCEDURE PsiWrite (s: Streams.Stream; data: Psi) : BOOLEAN; + (* writes the data structure for the private function psi onto a stream *) + CONST + index = M DIV 8; + VAR + dx, dy, r, d : INTEGER; + bytes : ARRAY index OF SYS.BYTE; + BEGIN + dy := 0; + WHILE dy < Dim DO + dx := 0; + WHILE dx < Dim DO + IF ~NetIO.WriteSet(s, data.initialmatrix[dy][dx]) THEN + RETURN FALSE; + END; + INC(dx); + END; + INC(dy); + END; + r := 0; + WHILE r < Rounds DO + d := 0; + WHILE d < Dim DO + IF ~NetIO.WriteSet(s, data.korrNum[r][d]) THEN + RETURN FALSE; + END; + INC(d); + END; + IF ~NetIO.WriteSet(s, data.korrDenom[r]) THEN + RETURN FALSE; + END; + INC(r); + END; + RETURN TRUE; + END PsiWrite; + + PROCEDURE PsiRead (s: Streams.Stream; VAR data: Psi) : BOOLEAN; + (* reads the data structure for the private function psi from a stream *) + CONST + index = M DIV 8; + VAR + dy, dx, r, d : INTEGER; + bytes : ARRAY index OF SYS.BYTE; + BEGIN + dy := 0; + WHILE dy < Dim DO + dx := 0; + WHILE dx < Dim DO + IF ~NetIO.ReadSet(s, data.initialmatrix[dy][dx]) THEN + RETURN FALSE; + END; + INC(dx); + END; + INC(dy); + END; + r := 0; + WHILE r < Rounds DO + d := 0; + WHILE d < Dim DO + IF ~NetIO.ReadSet(s, data.korrNum[r][d]) THEN + RETURN FALSE; + END; + INC(d); + END; + IF ~NetIO.ReadSet(s, data.korrDenom[r]) THEN + RETURN FALSE; + END; + INC(r); + END; + RETURN TRUE; + END PsiRead; + + PROCEDURE EtaWrite (s: Streams.Stream; data: Eta) : BOOLEAN; + (* writes the data structure for the public function eta onto a stream *) + VAR + l, d : INTEGER; + BEGIN + l := 0; + WHILE l < LastRounds DO + d := 0; + WHILE d < Dim DO + IF ~WritePolynom(s, data.p[l][d]) THEN + RETURN FALSE; + END; + INC(d); + END; + INC(l); + END; + RETURN TRUE; + END EtaWrite; + + PROCEDURE EtaRead (s: Streams.Stream; VAR data: Eta) : BOOLEAN; + (* reads the data structure for the public function eta from a stream *) + VAR + l, d : INTEGER; + BEGIN + NEW(data); + l := 0; + WHILE l < LastRounds DO + d := 0; + WHILE d < Dim DO + IF ~ReadPolynom(s, data.p[l][d]) THEN + RETURN FALSE; + END; + INC(d); + END; + INC(l); + END; + RETURN TRUE; + END EtaRead; + + PROCEDURE PubWrite (s: Streams.Stream; + obj: PersistentObjects.Object) : BOOLEAN; + (* interface procedure for PersistentObjects *) + BEGIN + WITH obj:PublicCipher DO + RETURN PhiWrite(s, obj.phi) & EtaWrite(s, obj.eta); + END; + END PubWrite; + + PROCEDURE CipherWrite (s: Streams.Stream; + obj: PersistentObjects.Object) : BOOLEAN; + (* interface procedure for PersistentObjects *) + BEGIN + WITH obj:PrivateCipher DO + RETURN PhiWrite(s, obj.phi) & + PsiWrite(s, obj.psi) & + EtaWrite(s, obj.eta); + END; + END CipherWrite; + + PROCEDURE PubRead (s: Streams.Stream; + obj: PersistentObjects.Object) : BOOLEAN; + (* interface procedure for PersistentObjects *) + BEGIN + WITH obj:PublicCipher DO + IF ~PhiRead(s, obj.phi) OR ~EtaRead(s, obj.eta) THEN + RETURN FALSE; + END; + END; + RETURN TRUE; + END PubRead; + + PROCEDURE CipherRead (s: Streams.Stream; + obj: PersistentObjects.Object) : BOOLEAN; + (* interface procedure for PersistentObjects *) + BEGIN + WITH obj:PrivateCipher DO + IF ~PhiRead(s, obj.phi) OR + ~PsiRead(s, obj.psi) OR + ~EtaRead(s, obj.eta) THEN + RETURN FALSE; + END; + END; + RETURN TRUE; + END CipherRead; + +BEGIN + (* init of the zero and unit of CC(M) *) + NullCCM := {}; + EinsCCM := {0}; + + (* init of the zero exponent *) + k := 0; + WHILE k