source: trunk/CrypPlugins/QuadraticSieve/QuadraticSieve.cs @ 1883

Last change on this file since 1883 was 1883, checked in by Sven Rech, 11 years ago

Much much better presentation for quadratic sieve plug-in.

Thanks to Paul for his cool KeySearcher presentation design.

File size: 39.0 KB
Line 
1/*                             
2   Copyright 2009 Team CrypTool (Sven Rech,Dennis Nolte,Raoul Falk,Nils Kopal), Uni Duisburg-Essen
3
4   Licensed under the Apache License, Version 2.0 (the "License");
5   you may not use this file except in compliance with the License.
6   You may obtain a copy of the License at
7
8       http://www.apache.org/licenses/LICENSE-2.0
9
10   Unless required by applicable law or agreed to in writing, software
11   distributed under the License is distributed on an "AS IS" BASIS,
12   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   See the License for the specific language governing permissions and
14   limitations under the License.
15*/
16
17using System;
18using System.Collections;
19using System.Linq;
20using System.Text;
21using Cryptool.PluginBase;
22using Cryptool.PluginBase.IO;
23using Cryptool.PluginBase.Miscellaneous;
24using System.ComponentModel;
25using System.Threading;
26using System.IO;
27using System.Windows.Controls;
28using System.Windows.Threading;
29using System.Windows;
30using System.Reflection;
31using System.Numerics;
32using System.Collections.Generic;
33using System.Diagnostics;
34using Cryptool.P2P;
35
36namespace Cryptool.Plugins.QuadraticSieve
37{
38    /// <summary>
39    /// This class wraps the msieve algorithm in version 1.42 which you can find at http://www.boo.net/~jasonp/qs.html
40    /// It also extends the msieve functionality to multi threading
41    /// Many thanks to the author of msieve "jasonp_sf"
42    ///
43    /// For further information on quadratic sieve or msieve please have a look at the above mentioned URL
44    /// </summary>
45    [Author("Sven Rech", "rech@cryptool.org", "Uni Duisburg-Essen", "http://www.uni-due.de")]
46    [PluginInfo(false, "Quadratic Sieve", "Sieving Primes", "QuadraticSieve/DetailedDescription/Description.xaml", "QuadraticSieve/iconqs.png")]
47    class QuadraticSieve : DependencyObject, IThroughput
48    {
49        #region private variables
50
51        private readonly string directoryName;
52        private QuadraticSieveSettings settings;
53        private BigInteger inputNumber;
54        private BigInteger[] outputFactors;
55        private bool running;
56        private Queue relationPackageQueue;
57        private AutoResetEvent newRelationPackageEvent = new AutoResetEvent(false);
58        private IntPtr obj = IntPtr.Zero;
59        private volatile int threadcount = 0;
60        private ArrayList conf_list;
61        private Mutex conf_listMutex = new Mutex();
62        private bool userStopped = false;
63        private FactorManager factorManager;
64        private PeerToPeer peerToPeer;
65        private PeerToPeerStatusUpdater peerToPeerStatusUpdater;
66        private bool usePeer2Peer;
67        private bool otherPeerFinished;
68        private bool useGnuplot = false;
69        private StreamWriter gnuplotFile;
70        private double[] relationsPerMS;
71        private DateTime start_time;
72
73        private static Assembly msieveDLL = null;
74        private static Type msieve = null;
75        private static bool alreadyInUse = false;
76        private static Mutex alreadyInUseMutex = new Mutex();
77        private AutoResetEvent waitForConnection = new AutoResetEvent(false);
78
79        #endregion
80
81        #region events
82
83        public event StatusChangedEventHandler OnPluginStatusChanged;
84        public event GuiLogNotificationEventHandler OnGuiLogNotificationOccured;
85        public event PluginProgressChangedEventHandler OnPluginProgressChanged;
86        public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
87        public event PluginProgressChangedEventHandler OnPluginProcessChanged;
88
89        #endregion
90
91        #region public
92
93        /// <summary>
94        /// Constructor
95        ///
96        /// constructs a new QuadraticSieve plugin
97        /// </summary>
98        public QuadraticSieve()
99        {
100            Settings = new QuadraticSieveSettings(this);
101
102            directoryName = Path.Combine(DirectoryHelper.DirectoryLocalTemp, "msieve");
103            if (!Directory.Exists(directoryName)) Directory.CreateDirectory(directoryName);
104
105            QuickWatchPresentation = new QuadraticSievePresentation();
106
107            peerToPeer = new PeerToPeer(quadraticSieveQuickWatchPresentation, newRelationPackageEvent);
108            peerToPeerStatusUpdater = new PeerToPeerStatusUpdater(peerToPeer);
109            peerToPeer.P2PWarning += new PeerToPeer.P2PWarningHandler(peerToPeer_P2PWarning);
110           
111            quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
112            {
113                quadraticSieveQuickWatchPresentation.peer2peer.Visibility = settings.UsePeer2Peer ? Visibility.Visible : Visibility.Collapsed;               
114                quadraticSieveQuickWatchPresentation.timeLeft.Content = "-";
115                quadraticSieveQuickWatchPresentation.endTime.Content = "-";
116                quadraticSieveQuickWatchPresentation.coresUsed.Content = "-";
117            }
118            , null);
119        }
120
121        /// <summary>
122        /// Getter / Setter for the settings of this plugin
123        /// </summary>
124        public Cryptool.PluginBase.ISettings Settings
125        {
126            get { return this.settings; }
127            set
128            {
129                this.settings = (QuadraticSieveSettings)value;
130                this.settings.PropertyChanged += new PropertyChangedEventHandler(settings_PropertyChanged);
131            }
132        }
133
134        private void settings_PropertyChanged(object sender, PropertyChangedEventArgs e)
135        {
136            if (e.PropertyName == "UsePeer2Peer")
137            {
138                if (quadraticSieveQuickWatchPresentation != null)
139                {
140                    quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
141                    {
142                        quadraticSieveQuickWatchPresentation.peer2peer.Visibility = settings.UsePeer2Peer ? Visibility.Visible : Visibility.Collapsed;                       
143                    }, null);
144                }
145            }
146        }
147
148        /// <summary>
149        /// Called by the environment before executing this plugin
150        /// </summary>
151        public void PreExecution()
152        { 
153        }
154       
155        /// <summary>
156        /// Called by the environment to execute this plugin
157        /// </summary>
158        public void Execute()
159        {
160            if (checkInUse())
161                return;
162           
163            try
164            {
165                usePeer2Peer = settings.UsePeer2Peer;
166                if (usePeer2Peer && !P2PManager.IsConnected && P2PManager.IsConnecting)
167                {
168                    P2PManager.ConnectionManager.OnP2PConnectionStateChangeOccurred += HandleConnectionStateChange;
169                    GuiLogMessage("Connecting to Peer2Peer network... Please wait!", NotificationLevel.Info);
170                    waitForConnection.WaitOne();                   
171                    P2PManager.ConnectionManager.OnP2PConnectionStateChangeOccurred -= HandleConnectionStateChange;
172                }
173                else if (usePeer2Peer && !P2PManager.IsConnected)
174                {
175                    GuiLogMessage("No connection to Peer2Peer network. Sieving locally now but waiting for connection...", NotificationLevel.Warning);
176                    P2PManager.ConnectionManager.OnP2PConnectionStateChangeOccurred += OnP2PConnectionStateChangeOccurred;
177                    usePeer2Peer = false;
178                }
179
180                if (usePeer2Peer && (settings.Channel == null ||settings.Channel.Trim() == ""))
181                {
182                    GuiLogMessage("No channel for Peer2Peer network specified. Sieving locally now!", NotificationLevel.Warning);
183                    usePeer2Peer = false;
184                }
185                if (settings.UsePeer2Peer)
186                {
187                    peerToPeer.SetChannel(settings.Channel);
188                    peerToPeer.SetNumber(InputNumber);
189                }
190
191                if (useGnuplot)
192                    gnuplotFile = new StreamWriter(Path.Combine(directoryName, "gnuplot.dat"), false);
193
194                userStopped = false;
195                otherPeerFinished = false;
196
197                if (InputNumber != 0)
198                {
199                    if (InputNumber.ToString().Length >= 275)
200                    {
201                        GuiLogMessage("Input too big.", NotificationLevel.Error);
202                        return;
203                    }
204
205                    String info_message = "Starting quadratic sieve, please wait!";
206
207                    start_time = DateTime.Now;
208
209                    GuiLogMessage(info_message, NotificationLevel.Info);
210                    quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
211                    {
212                        quadraticSieveQuickWatchPresentation.ProgressRelationPackages.Clear();
213                        quadraticSieveQuickWatchPresentation.information.Content = info_message;
214                        quadraticSieveQuickWatchPresentation.endTime.Content = "-";
215                        quadraticSieveQuickWatchPresentation.timeLeft.Content = "-";
216                        quadraticSieveQuickWatchPresentation.elapsedTime.Content = "-";
217                        quadraticSieveQuickWatchPresentation.startTime.Content = ""+start_time;
218                        quadraticSieveQuickWatchPresentation.factorList.Items.Clear();
219                        quadraticSieveQuickWatchPresentation.factorInfo.Content = "Searching trivial factors!";
220                        if (usePeer2Peer)
221                            quadraticSieveQuickWatchPresentation.localSieving.Visibility = Visibility.Hidden;
222                        else
223                            quadraticSieveQuickWatchPresentation.localSieving.Visibility = Visibility.Visible;
224                    }
225                    , null);
226
227                    initMsieveDLL();
228                    factorManager = new FactorManager(msieve.GetMethod("getPrimeFactors"), msieve.GetMethod("getCompositeFactors"), InputNumber);
229                    factorManager.FactorsChanged += this.FactorsChanged;
230
231                    //Now factorize:               
232                    try
233                    {
234                        string file = Path.Combine(directoryName, "" + InputNumber + ".dat");
235                        if (settings.DeleteCache && File.Exists(file))
236                            File.Delete(file);
237                        MethodInfo start = msieve.GetMethod("start");
238                        start.Invoke(null, new object[] { InputNumber.ToString(), file });
239                        obj = IntPtr.Zero;
240                    }
241                    catch (Exception ex)
242                    {
243                        GuiLogMessage("Error using msieve. " + ex.Message, NotificationLevel.Error);
244                        stopThreads();
245                        return;
246                    }
247
248                    if (!userStopped)
249                    {
250                        String timeLeft_message = "0 seconds left";
251                        String endtime_message = "" + (DateTime.Now);
252
253                        GuiLogMessage(info_message, NotificationLevel.Info);
254                        quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
255                        {
256                            quadraticSieveQuickWatchPresentation.information.Content = "Sieving finished!";
257                            quadraticSieveQuickWatchPresentation.endTime.Content = endtime_message;
258                            quadraticSieveQuickWatchPresentation.timeLeft.Content = timeLeft_message;
259                            quadraticSieveQuickWatchPresentation.factorInfo.Content = "";
260                        }
261                        , null);
262
263                        Debug.Assert(factorManager.CalculateNumber() == InputNumber);
264                        OutputFactors = factorManager.getPrimeFactors();
265
266                        ProgressChanged(1, 1);
267                    }
268                    else
269                    {                       
270                        info_message = "Stopped by user!";
271
272                        GuiLogMessage(info_message, NotificationLevel.Info);
273                        quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
274                        {
275                            quadraticSieveQuickWatchPresentation.information.Content = info_message;
276                            quadraticSieveQuickWatchPresentation.endTime.Content = "-";
277                            quadraticSieveQuickWatchPresentation.timeLeft.Content = "-";
278                            quadraticSieveQuickWatchPresentation.startTime.Content = "-";
279                            quadraticSieveQuickWatchPresentation.elapsedTime.Content = "-";
280                            quadraticSieveQuickWatchPresentation.factorInfo.Content = "";
281                        }
282                        , null);
283                    }
284                }
285                if (useGnuplot)
286                    gnuplotFile.Close();
287            }
288            finally
289            {
290                alreadyInUse = false;
291                P2PManager.ConnectionManager.OnP2PConnectionStateChangeOccurred -= OnP2PConnectionStateChangeOccurred;
292            }
293        }
294
295        private void OnP2PConnectionStateChangeOccurred(object sender, bool newState)
296        {
297            usePeer2Peer = newState;
298            if (usePeer2Peer)
299                GuiLogMessage("Using Peer2Peer network now!", NotificationLevel.Info);
300            else
301                GuiLogMessage("Lost Peer2Peer network connection... Sieving locally now!", NotificationLevel.Info);
302        }
303
304        private void HandleConnectionStateChange(object sender, bool newState)
305        {
306            waitForConnection.Set();
307        }
308
309        private bool checkInUse()
310        {
311            try
312            {
313                alreadyInUseMutex.WaitOne();
314                if (alreadyInUse)
315                {
316                    GuiLogMessage("QuadraticSieve plugin is only allowed to execute ones at a time due to technical restrictions.", NotificationLevel.Error);
317                    return true;
318                }
319                else
320                {
321                    alreadyInUse = true;
322                    return false;
323                }
324            }
325            finally
326            {
327                alreadyInUseMutex.ReleaseMutex();
328            }
329        }
330       
331        /// <summary>
332        /// Called by the environment after execution
333        /// </summary>
334        public void PostExecution()
335        {
336        }
337
338        /// <summary>
339        /// Called by the environment to pause execution
340        /// </summary>
341        public void Pause()
342        {
343        }
344
345        /// <summary>
346        /// Called by the environment to stop execution
347        /// </summary>
348        public void Stop()
349        {           
350            if (obj != IntPtr.Zero)
351            {
352                stopThreads();
353                MethodInfo stop = msieve.GetMethod("stop");
354                stop.Invoke(null, new object[] { obj });
355            }
356            this.userStopped = true;
357        }
358
359        /// <summary>
360        /// Called by the environment to initialize this plugin
361        /// </summary>
362        public void Initialize()
363        {
364            settings.Initialize();
365        }
366
367        /// <summary>
368        /// Called by the environment to dispose this plugin
369        /// </summary>
370        public void Dispose()
371        {
372        }
373
374        /// <summary>
375        /// Getter / Setter for the input number which should be factorized
376        /// </summary>
377        [PropertyInfo(Direction.InputData, "Number input", "Enter the number you want to factorize", "", DisplayLevel.Beginner)]
378        public BigInteger InputNumber
379        {
380            get
381            {
382                return inputNumber;
383            }
384            set
385            {
386                this.inputNumber = value;
387                OnPropertyChanged("InputNumber");
388            }
389        }
390
391        /// <summary>
392        /// Getter / Setter for the factors calculated by msieve
393        /// </summary>
394        [PropertyInfo(Direction.OutputData, "Factors output", "Your factors will be sent here", "", DisplayLevel.Beginner)]
395        public BigInteger[] OutputFactors
396        {
397            get
398            {
399                return outputFactors;
400            }
401            set
402            {
403                this.outputFactors = value;
404                OnPropertyChanged("OutputFactors");
405            }
406        }
407       
408        /// <summary>
409        /// Called when a property of this plugin changes
410        /// </summary>
411        /// <param name="name">name</param>
412        public void OnPropertyChanged(string name)
413        {
414            EventsHelper.PropertyChanged(PropertyChanged, this, new PropertyChangedEventArgs(name));
415        }
416
417        /// <summary>
418        /// Getter / Setter for the presentation of this plugin
419        /// </summary>
420        public UserControl Presentation { get; private set; }
421
422        /// <summary>
423        /// Getter / Setter for the QuickWatchPresentation of this plugin
424        /// </summary>
425        public UserControl QuickWatchPresentation
426        {
427            get;
428            private set;
429        }
430
431        #endregion
432
433        #region private
434
435        /// <summary>
436        /// calculate a String which shows the timespan
437        ///
438        /// example
439        ///
440        ///     4 days
441        /// or
442        ///     2 minutes
443        /// </summary>
444        /// <param name="ts"></param>
445        /// <returns></returns>
446        private String timeSpanString(TimeSpan ts)
447        {
448            String res = "";
449            if (ts.Days != 0)
450                res = ts.Days + " days ";
451            if (ts.Hours != 0 || res.Length != 0)
452                res += ts.Hours + " hours ";
453            if (ts.Minutes != 0)
454                res += ts.Minutes + " minutes";
455            if (res.Length == 0)
456                res += ts.Seconds + " seconds";
457            return res;
458        }
459
460        /// <summary>
461        /// Callback method to prepare sieving
462        /// Called by msieve
463        ///
464        /// </summary>       
465        /// <param name="conf">pointer to configuration</param>
466        /// <param name="update">number of relations found</param>
467        /// <param name="core_sieve_fcn">pointer to internal sieve function of msieve</param>
468        /// <returns>true if enough relations found, false if not</returns>
469        private bool prepareSieving(IntPtr conf, int update, IntPtr core_sieve_fcn, int max_relations)
470        {
471            try
472            {
473                int threads = Math.Min(settings.CoresUsed, Environment.ProcessorCount - 1);
474                MethodInfo getObjFromConf = msieve.GetMethod("getObjFromConf");
475                this.obj = (IntPtr)getObjFromConf.Invoke(null, new object[] { conf });
476                relationPackageQueue = Queue.Synchronized(new Queue());
477                conf_list = new ArrayList();
478
479                String message = "Sieving now!";
480                GuiLogMessage(message, NotificationLevel.Info);
481                quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
482                {
483                    quadraticSieveQuickWatchPresentation.coresUsed.Content = (threads+1);
484                    quadraticSieveQuickWatchPresentation.information.Content = message;
485                    if (usePeer2Peer)
486                        quadraticSieveQuickWatchPresentation.localSieving.Visibility = Visibility.Hidden;
487                }
488                , null);
489
490                ProgressChanged(0.1, 1.0);
491
492                running = true;
493                //start helper threads:
494                relationsPerMS = new double[threads + 1];
495                for (int i = 0; i < threads + 1; i++)
496                {
497                    MethodInfo cloneSieveConf = msieve.GetMethod("cloneSieveConf");
498                    IntPtr clone = (IntPtr)cloneSieveConf.Invoke(null, new object[] { conf });
499                    conf_list.Add(clone);
500                    WaitCallback worker = new WaitCallback(MSieveJob);
501                    ThreadPool.QueueUserWorkItem(worker, new object[] { clone, update, core_sieve_fcn, relationPackageQueue, i });
502                }
503
504                //manage the relation packages of the other threads:
505                manageRelationPackages(conf, max_relations);  //this method returns as soon as there are enough relations found
506                if (userStopped)
507                    return false;
508
509                //sieving is finished now, so give some informations and stop threads:
510                ProgressChanged(0.9, 1.0);
511                GuiLogMessage("Sieving finished", NotificationLevel.Info);
512                quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
513                {
514                    quadraticSieveQuickWatchPresentation.timeLeft.Content = "-";
515                    quadraticSieveQuickWatchPresentation.endTime.Content = "-";
516                    quadraticSieveQuickWatchPresentation.factorInfo.Content = "Found enough relations! Please wait...";
517                }, null);
518
519                if (relationPackageQueue != null)
520                    relationPackageQueue.Clear();
521            }
522            catch (AlreadySievedException)
523            {
524                ProgressChanged(0.9, 1.0);
525                GuiLogMessage("Another peer already finished factorization of composite factor. Sieving next one...", NotificationLevel.Info);
526                quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
527                {
528                    quadraticSieveQuickWatchPresentation.timeLeft.Content = "-";
529                    quadraticSieveQuickWatchPresentation.endTime.Content = "-";
530                    quadraticSieveQuickWatchPresentation.factorInfo.Content = "Other peer finished sieving!";
531                }, null);
532                otherPeerFinished = true;
533                return false;
534            }
535            finally
536            {
537                stopThreads();
538            }
539            return true;
540        }
541
542        /// <summary>
543        /// Manages the whole relation packages that are created during the sieving process by the other threads (and other peers).
544        /// Returns true, if enough relations have been found.
545        /// </summary>
546        private void manageRelationPackages(IntPtr conf, int max_relations)
547        {
548            MethodInfo serializeRelationPackage = msieve.GetMethod("serializeRelationPackage");
549            MethodInfo deserializeRelationPackage = msieve.GetMethod("deserializeRelationPackage");
550            MethodInfo getNumRelations = msieve.GetMethod("getNumRelations");
551            int num_relations = (int)getNumRelations.Invoke(null, new object[] { conf });
552            int start_relations = num_relations;
553            DateTime start_sieving_time = DateTime.Now;
554            MethodInfo saveRelationPackage = msieve.GetMethod("saveRelationPackage");
555
556            while (num_relations < max_relations)
557            {
558                double progress = (double)num_relations / max_relations * 0.8 + 0.1;
559                ProgressChanged(progress, 1.0);               
560               
561                newRelationPackageEvent.WaitOne();               //wait until there is a new relation package in the queue
562                if (userStopped)
563                    return;
564
565                while (relationPackageQueue.Count != 0)       //get all the results from the helper threads, and store them
566                {
567                    IntPtr relationPackage = (IntPtr)relationPackageQueue.Dequeue();
568
569                    if (settings.UsePeer2Peer)
570                    {
571                        byte[] serializedRelationPackage = (byte[])serializeRelationPackage.Invoke(null, new object[] { relationPackage });
572                        peerToPeer.Put(serializedRelationPackage);
573                    }
574
575                    saveRelationPackage.Invoke(null, new object[] { conf, relationPackage });
576                }
577
578                if (usePeer2Peer)
579                {
580                    Queue dhtqueue = peerToPeer.GetLoadedRelationPackagesQueue();
581                    while (dhtqueue.Count != 0)       //get all the loaded results from the DHT, and store them
582                    {
583                        byte[] relationPackage = (byte[])dhtqueue.Dequeue();
584                        IntPtr deserializedRelationPackage = (IntPtr)deserializeRelationPackage.Invoke(null, new object[] { relationPackage });
585                        saveRelationPackage.Invoke(null, new object[] { conf, deserializedRelationPackage });
586                    }
587                }
588
589                num_relations = (int)getNumRelations.Invoke(null, new object[] { conf });
590                showProgressPresentation(max_relations, num_relations, start_relations, start_sieving_time);
591
592                if (usePeer2Peer && !peerToPeer.SyncFactorManager(factorManager))   //another peer already finished sieving
593                {
594                    throw new AlreadySievedException();
595                }
596            }           
597        }
598
599        private void showProgressPresentation(int max_relations, int num_relations, int start_relations, DateTime start_sieving_time)
600        {
601            double msleft = 0;
602
603            //calculate global performance in relations per ms:
604            double globalPerformance = 0;
605            foreach (double r in relationsPerMS)
606                globalPerformance += r;
607            if (usePeer2Peer)
608                globalPerformance += peerToPeer.GetP2PPerformance();
609
610            //Calculate the total time assuming that we can sieve 1 minute with the same performance:
611            double relationsCalculatableIn1Minute = 1000 * 60 * 1 * globalPerformance;
612            if (relationsCalculatableIn1Minute <= max_relations)
613            {
614                double p = ApproximatedPolynom(relationsCalculatableIn1Minute / max_relations);
615                double estimatedTotalTime = 1000 * 60 * 1 / p;
616
617                //Calculate the elapsed time assuming that we sieved with the same performance the whole time:
618                p = ApproximatedPolynom((double)num_relations / max_relations);
619                double estimatedElapsedTime = estimatedTotalTime * p;
620
621                //Calculate time left:
622                msleft = estimatedTotalTime - estimatedElapsedTime;
623            }           
624           
625            String timeLeft_message = "very soon";
626            String endtime_message = "very soon";
627            DateTime now = DateTime.Now;
628            if (msleft > 0 && !double.IsInfinity(msleft))
629            {
630                TimeSpan ts = new TimeSpan(0, 0, 0, 0, (int)msleft);
631                timeLeft_message = timeSpanString(ts) + " left";
632                endtime_message = "" + now.AddMilliseconds((long)msleft);
633            }
634
635            if (globalPerformance == 0 || double.IsInfinity(msleft))
636            {
637                timeLeft_message = "-";
638                endtime_message = "-";
639            }
640
641            quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
642            {
643                quadraticSieveQuickWatchPresentation.foundRelations.Content = num_relations;
644                quadraticSieveQuickWatchPresentation.maxRelations.Content = max_relations;
645                quadraticSieveQuickWatchPresentation.timeLeft.Content = timeLeft_message;
646                quadraticSieveQuickWatchPresentation.endTime.Content = endtime_message;
647                quadraticSieveQuickWatchPresentation.elapsedTime.Content = timeSpanString(now.Subtract(start_time));
648            }, null);
649
650            if (useGnuplot)
651            {
652                double percentage = (double)num_relations / max_relations;
653                double time = (DateTime.Now - start_sieving_time).TotalSeconds;
654                gnuplotFile.WriteLine("" + time + "\t\t" + percentage);
655            }
656        }
657
658        private static double ApproximatedPolynom(double x)
659        {
660            double a = -3.55504;
661            double b = 8.62296;
662            double c = -7.75103;
663            double d = 3.65871;
664            double progress = a * x * x * x * x + b * x * x * x + c * x * x + d * x;
665            return progress;
666        }
667
668        /// <summary>
669        /// This callback method is called by msieve. "list" is the trivial factor list (i.e. it consists of the factors that have been found without
670        /// using the quadratic sieve algorithm).
671        /// The method then factors all the factors that are still composite by using the quadratic sieve.
672        /// </summary>
673        private void putTrivialFactorlist(IntPtr list, IntPtr obj)
674        {
675            if (userStopped)
676                return;
677
678            //add the trivial factors to the factor list:
679            factorManager.AddFactors(list);
680
681            if (usePeer2Peer)
682                peerToPeer.SyncFactorManager(factorManager);
683           
684            MethodInfo msieve_run_core = msieve.GetMethod("msieve_run_core");
685
686            try
687            {
688                //Now factorize as often as needed:
689                while (!factorManager.OnlyPrimes())
690                {
691                    //get one composite factor, which we want to sieve now:
692                    BigInteger compositeFactor = factorManager.GetCompositeFactor();
693                    showFactorInformations(compositeFactor);
694                    if (settings.UsePeer2Peer)
695                        peerToPeer.SetFactor(compositeFactor);
696
697                    //now start quadratic sieve on it:               
698                    IntPtr resultList = (IntPtr)msieve_run_core.Invoke(null, new object[2] { obj, compositeFactor.ToString() });
699                    if (otherPeerFinished)
700                    {
701                        otherPeerFinished = false;
702                        continue;
703                    }
704
705                    if (resultList == IntPtr.Zero)
706                        throw new NotSievableException();
707
708                    if (userStopped)
709                        return;
710
711                    factorManager.ReplaceCompositeByFactors(compositeFactor, resultList);   //add the result list to factorManager
712
713                    if (usePeer2Peer)
714                        peerToPeer.SyncFactorManager(factorManager);
715                }
716            }
717            catch (NotSievableException)
718            {
719                GuiLogMessage("This number is not sievable by msieve (maybe input too long?)", NotificationLevel.Error);
720            }
721        }
722
723        private void showFactorInformations(BigInteger compositeFactor)
724        {
725            quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
726            {
727                String compRep;
728                if (compositeFactor.ToString().Length < 50)
729                    compRep = compositeFactor.ToString();
730                else
731                    compRep = compositeFactor.ToString().Substring(0, 48) + "...";
732                quadraticSieveQuickWatchPresentation.factorInfo.Content = "Now sieving first composite factor! (" + compRep + ")";
733            }, null);
734        }
735
736        /// <summary>
737        /// Helper Thread for msieve, which sieves for relations:
738        /// </summary>
739        /// <param name="param">params</param>
740        private void MSieveJob(object param)
741        {
742            threadcount++;
743            object[] parameters = (object[])param;
744            IntPtr clone = (IntPtr)parameters[0];
745            int update = (int)parameters[1];
746            IntPtr core_sieve_fcn = (IntPtr)parameters[2];
747            Queue relationPackageQueue = (Queue)parameters[3];
748            int threadNR = (int)parameters[4];
749
750            try
751            {
752                MethodInfo collectRelations = msieve.GetMethod("collectRelations");
753                MethodInfo getRelationPackage = msieve.GetMethod("getRelationPackage");
754                MethodInfo getAmountOfRelationsInRelationPackage = msieve.GetMethod("getAmountOfRelationsInRelationPackage");
755
756                Thread.CurrentThread.Priority = ThreadPriority.BelowNormal;
757
758                while (running)
759                {
760                    try
761                    {
762                        //Calculate the performance of this thread:
763                        DateTime beginning = DateTime.Now;
764                        collectRelations.Invoke(null, new object[] { clone, update, core_sieve_fcn });
765                        IntPtr relationPackage = (IntPtr)getRelationPackage.Invoke(null, new object[] { clone });
766
767                        int amountOfFullRelations = (int)getAmountOfRelationsInRelationPackage.Invoke(null, new object[] { relationPackage });
768                        relationsPerMS[threadNR] = amountOfFullRelations / (DateTime.Now - beginning).TotalMilliseconds;
769
770                        if (usePeer2Peer)
771                            peerToPeer.SetOurPerformance(relationsPerMS);
772
773                        relationPackageQueue.Enqueue(relationPackage);
774                        newRelationPackageEvent.Set();
775                    }
776                    catch (Exception ex)
777                    {
778                        GuiLogMessage("Error using msieve." + ex.Message, NotificationLevel.Error);
779                        threadcount = 0;
780                        return;
781                    }
782                }
783
784                conf_listMutex.WaitOne();
785                if (conf_list != null)
786                    conf_list[threadNR] = null;
787                MethodInfo freeSieveConf = msieve.GetMethod("freeSieveConf");
788                freeSieveConf.Invoke(null, new object[] { clone });
789                conf_listMutex.ReleaseMutex();
790            }
791            finally
792            {
793                threadcount--;
794            }
795        }       
796
797        /// <summary>
798        /// Stop all running threads
799        /// </summary>
800        private void stopThreads()
801        {
802            if (settings.UsePeer2Peer)
803                peerToPeer.StopLoadStoreThread();
804
805            if (conf_list != null)
806            {
807                MethodInfo stop = msieve.GetMethod("stop");
808                MethodInfo getObjFromConf = msieve.GetMethod("getObjFromConf");
809
810                conf_listMutex.WaitOne();
811                foreach (Object conf in conf_list)
812                    if (conf != null)
813                        stop.Invoke(null, new object[] { getObjFromConf.Invoke(null, new object[] { (IntPtr)conf }) });
814               
815                running = false;
816
817                conf_list = null;
818                conf_listMutex.ReleaseMutex();
819
820                GuiLogMessage("Waiting for threads to stop!", NotificationLevel.Debug);
821                while (threadcount > 0)
822                {
823                    Thread.Sleep(0);
824                }
825                GuiLogMessage("Threads stopped!", NotificationLevel.Debug);
826            }
827        }   
828
829        /// <summary>
830        /// Change the progress of this plugin
831        /// </summary>
832        /// <param name="value">value</param>
833        /// <param name="max">max</param>
834        private void ProgressChanged(double value, double max)
835        {
836            EventsHelper.ProgressChanged(OnPluginProgressChanged, this, new PluginProgressEventArgs(value, max));
837            if (usePeer2Peer)
838                peerToPeerStatusUpdater.UpdateStatus(value/max);
839        }
840
841        private void FactorsChanged(List<BigInteger> primeFactors, List<BigInteger> compositeFactors)
842        {
843            quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
844            {
845                quadraticSieveQuickWatchPresentation.factorList.Items.Clear();
846
847                foreach (BigInteger pf in primeFactors)         
848                    quadraticSieveQuickWatchPresentation.factorList.Items.Add("Prime Factor: " + pf.ToString());           
849
850                foreach (BigInteger cf in compositeFactors)
851                    quadraticSieveQuickWatchPresentation.factorList.Items.Add("Composite Factor: " + cf.ToString());
852                quadraticSieveQuickWatchPresentation.SelectFirstComposite();
853            }, null);
854        }
855
856        /// <summary>
857        /// Getter / Setter for the QuickWatchPresentation
858        /// </summary>
859        private QuadraticSievePresentation quadraticSieveQuickWatchPresentation
860        {
861            get { return QuickWatchPresentation as QuadraticSievePresentation; }
862        }
863
864        /// <summary>
865        /// dynamically loads the msieve dll file and sets the callbacks
866        /// </summary>
867        private void initMsieveDLL()
868        {
869            msieveDLL = Msieve.GetMsieveDLL();
870            msieve = msieveDLL.GetType("Msieve.msieve");
871
872            //init msieve with callbacks:
873            MethodInfo initMsieve = msieve.GetMethod("initMsieve");
874            Object callback_struct = Activator.CreateInstance(msieveDLL.GetType("Msieve.callback_struct"));           
875            FieldInfo prepareSievingField = msieveDLL.GetType("Msieve.callback_struct").GetField("prepareSieving");
876            FieldInfo putTrivialFactorlistField = msieveDLL.GetType("Msieve.callback_struct").GetField("putTrivialFactorlist");           
877            Delegate prepareSievingDel = MulticastDelegate.CreateDelegate(msieveDLL.GetType("Msieve.prepareSievingDelegate"), this, "prepareSieving");
878            Delegate putTrivialFactorlistDel = MulticastDelegate.CreateDelegate(msieveDLL.GetType("Msieve.putTrivialFactorlistDelegate"), this, "putTrivialFactorlist");           
879            prepareSievingField.SetValue(callback_struct, prepareSievingDel);
880            putTrivialFactorlistField.SetValue(callback_struct, putTrivialFactorlistDel);
881            initMsieve.Invoke(null, new object[1] { callback_struct });
882        }
883
884        private void peerToPeer_P2PWarning(string warning)
885        {
886            GuiLogMessage(warning, NotificationLevel.Warning);
887        }
888
889        #endregion
890
891        #region internal
892
893        internal PeerToPeer PeerToPeer
894        {
895            get { return peerToPeer; }
896        }
897
898        internal bool Running
899        {
900            get { return running; }
901        }
902
903        /// <summary>
904        /// Logs a message to the CrypTool gui
905        /// </summary>
906        /// <param name="p">p</param>
907        /// <param name="notificationLevel">notificationLevel</param>
908        internal void GuiLogMessage(string p, NotificationLevel notificationLevel)
909        {
910            EventsHelper.GuiLogMessage(OnGuiLogNotificationOccured, this, new GuiLogEventArgs(p, this, notificationLevel));
911        }
912
913        #endregion
914
915    }
916}
Note: See TracBrowser for help on using the repository browser.